@@ -1354,62 +1354,102 @@ func (c *Checker) getVariancesWorker(symbol *ast.Symbol, typeParameters []*Type)
13541354 popFn ()
13551355 }()
13561356 }
1357- oldVarianceComputation := c .inVarianceComputation
1358- saveResolutionStart := c .resolutionStart
1359- if ! c .inVarianceComputation {
1360- c .inVarianceComputation = true
1361- c .resolutionStart = len (c .typeResolutions )
1362- }
1363- links .variances = []VarianceFlags {}
1364- variances := make ([]VarianceFlags , len (typeParameters ))
1365- for i , tp := range typeParameters {
1366- modifiers := c .getTypeParameterModifiers (tp )
1367- var variance VarianceFlags
1368- switch {
1369- case modifiers & ast .ModifierFlagsOut != 0 :
1370- if modifiers & ast .ModifierFlagsIn != 0 {
1371- variance = VarianceFlagsInvariant
1372- } else {
1373- variance = VarianceFlagsCovariant
1374- }
1375- case modifiers & ast .ModifierFlagsIn != 0 :
1376- variance = VarianceFlagsContravariant
1377- default :
1378- saveReliabilityFlags := c .reliabilityFlags
1379- c .reliabilityFlags = 0
1380- // We first compare instantiations where the type parameter is replaced with
1381- // marker types that have a known subtype relationship. From this we can infer
1382- // invariance, covariance, contravariance or bivariance.
1383- typeWithSuper := c .createMarkerType (symbol , tp , c .markerSuperType )
1384- typeWithSub := c .createMarkerType (symbol , tp , c .markerSubType )
1385- variance = core .IfElse (c .isTypeAssignableTo (typeWithSub , typeWithSuper ), VarianceFlagsCovariant , 0 ) |
1386- core .IfElse (c .isTypeAssignableTo (typeWithSuper , typeWithSub ), VarianceFlagsContravariant , 0 )
1387- // If the instantiations appear to be related bivariantly it may be because the
1388- // type parameter is independent (i.e. it isn't witnessed anywhere in the generic
1389- // type). To determine this we compare instantiations where the type parameter is
1390- // replaced with marker types that are known to be unrelated.
1391- if variance == VarianceFlagsBivariant && c .isTypeAssignableTo (c .createMarkerType (symbol , tp , c .markerOtherType ), typeWithSuper ) {
1392- variance = VarianceFlagsIndependent
1357+ stackIndex := c .getVarianceStackIndex (symbol )
1358+ if stackIndex < 0 {
1359+ saveResolutionStart := c .resolutionStart
1360+ if len (c .varianceStack ) == 0 {
1361+ c .resolutionStart = len (c .typeResolutions )
1362+ }
1363+ c .varianceStack = append (c .varianceStack , VarianceStackEntry {symbol , typeParameters })
1364+ variances := make ([]VarianceFlags , len (typeParameters ))
1365+ for i , tp := range typeParameters {
1366+ modifiers := c .getTypeParameterModifiers (tp )
1367+ var variance VarianceFlags
1368+ switch {
1369+ case modifiers & ast .ModifierFlagsOut != 0 :
1370+ if modifiers & ast .ModifierFlagsIn != 0 {
1371+ variance = VarianceFlagsInvariant
1372+ } else {
1373+ variance = VarianceFlagsCovariant
1374+ }
1375+ case modifiers & ast .ModifierFlagsIn != 0 :
1376+ variance = VarianceFlagsContravariant
1377+ default :
1378+ saveReliabilityFlags := c .reliabilityFlags
1379+ c .reliabilityFlags = 0
1380+ // We first compare instantiations where the type parameter is replaced with
1381+ // marker types that have a known subtype relationship. From this we can infer
1382+ // invariance, covariance, contravariance or bivariance.
1383+ typeWithSuper := c .createMarkerType (symbol , tp , c .markerSuperType )
1384+ typeWithSub := c .createMarkerType (symbol , tp , c .markerSubType )
1385+ variance = core .IfElse (c .isTypeAssignableTo (typeWithSub , typeWithSuper ), VarianceFlagsCovariant , 0 ) |
1386+ core .IfElse (c .isTypeAssignableTo (typeWithSuper , typeWithSub ), VarianceFlagsContravariant , 0 )
1387+ // If the instantiations appear to be related bivariantly it may be because the
1388+ // type parameter is independent (i.e. it isn't witnessed anywhere in the generic
1389+ // type). To determine this we compare instantiations where the type parameter is
1390+ // replaced with marker types that are known to be unrelated.
1391+ if variance == VarianceFlagsBivariant && c .isTypeAssignableTo (c .createMarkerType (symbol , tp , c .markerOtherType ), typeWithSuper ) {
1392+ variance = VarianceFlagsIndependent
1393+ }
1394+ if c .reliabilityFlags & RelationComparisonResultReportsUnmeasurable != 0 {
1395+ variance |= VarianceFlagsUnmeasurable
1396+ }
1397+ if c .reliabilityFlags & RelationComparisonResultReportsUnreliable != 0 {
1398+ variance |= VarianceFlagsUnreliable
1399+ }
1400+ c .reliabilityFlags = saveReliabilityFlags
13931401 }
1394- if c .reliabilityFlags & RelationComparisonResultReportsUnmeasurable != 0 {
1395- variance |= VarianceFlagsUnmeasurable
1402+ // If variance computation was restarted due to a circularity we may have already
1403+ // computed variances for this generic type. If so, we exit early.
1404+ if len (links .variances ) != 0 {
1405+ break
13961406 }
1397- if c .reliabilityFlags & RelationComparisonResultReportsUnreliable != 0 {
1398- variance |= VarianceFlagsUnreliable
1407+ variances [i ] = variance
1408+ }
1409+ // Store the results unless a restarted computation has already stored them.
1410+ if len (links .variances ) == 0 {
1411+ links .variances = variances
1412+ }
1413+ c .varianceStack = c .varianceStack [:len (c .varianceStack )- 1 ]
1414+ if len (c .varianceStack ) == 0 {
1415+ c .resolutionStart = saveResolutionStart
1416+ }
1417+ } else {
1418+ // We've detected a circularity. Since we may compute different variances depending on where
1419+ // we enter a circularity, we find the generic type with the "smallest" symbol in the circular
1420+ // region of the variance stack and restart the computation from there if necessary. This
1421+ // ensures stable results for circular generic types.
1422+ minIndex := stackIndex
1423+ for i := stackIndex + 1 ; i < len (c .varianceStack ); i ++ {
1424+ if c .compareSymbols (c .varianceStack [i ].symbol , c .varianceStack [minIndex ].symbol ) < 0 {
1425+ minIndex = i
13991426 }
1400- c .reliabilityFlags = saveReliabilityFlags
14011427 }
1402- variances [i ] = variance
1403- }
1404- if ! oldVarianceComputation {
1405- c .inVarianceComputation = false
1406- c .resolutionStart = saveResolutionStart
1428+ if minIndex > stackIndex {
1429+ saveVarianceStack := c .varianceStack
1430+ c .varianceStack = nil
1431+ c .getVariancesWorker (saveVarianceStack [minIndex ].symbol , saveVarianceStack [minIndex ].typeParameters )
1432+ c .varianceStack = saveVarianceStack
1433+ }
1434+ // Store an empty slice to mark that we can't compute variances for this type. We treat type
1435+ // parameters as co-variant in this case.
1436+ if len (links .variances ) == 0 {
1437+ links .variances = []VarianceFlags {}
1438+ }
14071439 }
1408- links .variances = variances
14091440 }
14101441 return links .variances
14111442}
14121443
1444+ func (c * Checker ) getVarianceStackIndex (symbol * ast.Symbol ) int {
1445+ for i , entry := range c .varianceStack {
1446+ if entry .symbol == symbol {
1447+ return i
1448+ }
1449+ }
1450+ return - 1
1451+ }
1452+
14131453func (c * Checker ) createMarkerType (symbol * ast.Symbol , source * Type , target * Type ) * Type {
14141454 mapper := newSimpleTypeMapper (source , target )
14151455 t := c .getDeclaredTypeOfSymbol (symbol )
@@ -3930,8 +3970,8 @@ func (r *Relater) typeArgumentsRelatedTo(sources []*Type, targets []*Type, varia
39303970 related = r .c .compareTypesIdentical (s , t )
39313971 }
39323972 } else {
3933- // Propagate unreliable variance flag
3934- if r .c .inVarianceComputation && varianceFlags & VarianceFlagsUnreliable != 0 {
3973+ // Propagate unreliable variance flag in variance computations
3974+ if len ( r .c .varianceStack ) != 0 && varianceFlags & VarianceFlagsUnreliable != 0 {
39353975 r .c .instantiateType (s , r .c .reportUnreliableMapper )
39363976 }
39373977 if variance == VarianceFlagsCovariant {
0 commit comments