@@ -1332,8 +1332,8 @@ func (c *Checker) getAliasVariances(symbol *ast.Symbol) []VarianceFlags {
13321332// instantiations of the generic type for type arguments with known relations. The function
13331333// returns an empty slice when invoked recursively for the given generic type.
13341334func (c * Checker ) getVariancesWorker (symbol * ast.Symbol , typeParameters []* Type ) []VarianceFlags {
1335- links := c .varianceLinks .Get (symbol )
1336- if links .variances == nil {
1335+ links := c .varianceLinks .Get (symbol )
1336+ if links .variances == nil {
13371337 var traceArgs map [string ]any
13381338 if tr := c .tracer ; tr != nil {
13391339 traceArgs = map [string ]any {"arity" : len (typeParameters ), "id" : c .getDeclaredTypeOfSymbol (symbol ).id }
@@ -1348,88 +1348,62 @@ func (c *Checker) getVariancesWorker(symbol *ast.Symbol, typeParameters []*Type)
13481348 }()
13491349 }
13501350 stackIndex := c .getVarianceStackIndex (symbol )
1351- if stackIndex < 0 {
1352- saveResolutionStart := c .resolutionStart
1353- if len (c .varianceStack ) == 0 {
1354- c .resolutionStart = len (c .typeResolutions )
1355- }
1356- c .varianceStack = append (c .varianceStack , VarianceStackEntry {symbol , typeParameters })
1357- variances := make ([]VarianceFlags , len (typeParameters ))
1358- for i , tp := range typeParameters {
1359- modifiers := c .getTypeParameterModifiers (tp )
1360- var variance VarianceFlags
1361- switch {
1362- case modifiers & ast .ModifierFlagsOut != 0 :
1363- if modifiers & ast .ModifierFlagsIn != 0 {
1364- variance = VarianceFlagsInvariant
1365- } else {
1366- variance = VarianceFlagsCovariant
1367- }
1368- case modifiers & ast .ModifierFlagsIn != 0 :
1369- variance = VarianceFlagsContravariant
1370- default :
1371- saveReliabilityFlags := c .reliabilityFlags
1372- c .reliabilityFlags = 0
1373- // We first compare instantiations where the type parameter is replaced with
1374- // marker types that have a known subtype relationship. From this we can infer
1375- // invariance, covariance, contravariance or bivariance.
1376- typeWithSuper := c .createMarkerType (symbol , tp , c .markerSuperType )
1377- typeWithSub := c .createMarkerType (symbol , tp , c .markerSubType )
1378- variance = core .IfElse (c .isTypeAssignableTo (typeWithSub , typeWithSuper ), VarianceFlagsCovariant , 0 ) |
1379- core .IfElse (c .isTypeAssignableTo (typeWithSuper , typeWithSub ), VarianceFlagsContravariant , 0 )
1380- // If the instantiations appear to be related bivariantly it may be because the
1381- // type parameter is independent (i.e. it isn't witnessed anywhere in the generic
1382- // type). To determine this we compare instantiations where the type parameter is
1383- // replaced with marker types that are known to be unrelated.
1384- if variance == VarianceFlagsBivariant && c .isTypeAssignableTo (c .createMarkerType (symbol , tp , c .markerOtherType ), typeWithSuper ) {
1385- variance = VarianceFlagsIndependent
1386- }
1387- if c .reliabilityFlags & RelationComparisonResultReportsUnmeasurable != 0 {
1388- variance |= VarianceFlagsUnmeasurable
1389- }
1390- if c .reliabilityFlags & RelationComparisonResultReportsUnreliable != 0 {
1391- variance |= VarianceFlagsUnreliable
1392- }
1393- c .reliabilityFlags = saveReliabilityFlags
1394- }
1395- // If variance computation was restarted due to a circularity we may have already
1396- // computed variances for this generic type. If so, we exit early.
1397- if len (links .variances ) != 0 {
1398- break
1399- }
1400- variances [i ] = variance
1401- }
1402- // Store the results unless a restarted computation has already stored them.
1403- if len (links .variances ) == 0 {
1404- links .variances = variances
1405- }
1406- c .varianceStack = c .varianceStack [:len (c .varianceStack )- 1 ]
1407- if len (c .varianceStack ) == 0 {
1408- c .resolutionStart = saveResolutionStart
1409- }
1351+ if stackIndex < 0 {
1352+ saveResolutionStart := c .resolutionStart
1353+ if len (c .varianceStack ) == 0 {
1354+ c .resolutionStart = len (c .typeResolutions )
1355+ }
1356+ c .varianceStack = append (c .varianceStack , VarianceStackEntry {symbol , typeParameters })
1357+ variances := make ([]VarianceFlags , len (typeParameters ))
1358+ for i , tp := range typeParameters {
1359+ modifiers := c .getTypeParameterModifiers (tp )
1360+ var variance VarianceFlags
1361+ switch {
1362+ case modifiers & ast .ModifierFlagsOut != 0 :
1363+ if modifiers & ast .ModifierFlagsIn != 0 {
1364+ variance = VarianceFlagsInvariant
1365+ } else {
1366+ variance = VarianceFlagsCovariant
1367+ }
1368+ case modifiers & ast .ModifierFlagsIn != 0 :
1369+ variance = VarianceFlagsContravariant
1370+ default :
1371+ saveReliabilityFlags := c .reliabilityFlags
1372+ c .reliabilityFlags = 0
1373+ typeWithSuper := c .createMarkerType (symbol , tp , c .markerSuperType )
1374+ typeWithSub := c .createMarkerType (symbol , tp , c .markerSubType )
1375+ variance = core .IfElse (c .isTypeAssignableTo (typeWithSub , typeWithSuper ), VarianceFlagsCovariant , 0 ) |
1376+ core .IfElse (c .isTypeAssignableTo (typeWithSuper , typeWithSub ), VarianceFlagsContravariant , 0 )
1377+ if variance == VarianceFlagsBivariant && c .isTypeAssignableTo (c .createMarkerType (symbol , tp , c .markerOtherType ), typeWithSuper ) {
1378+ variance = VarianceFlagsIndependent
1379+ }
1380+ if c .reliabilityFlags & RelationComparisonResultReportsUnmeasurable != 0 {
1381+ variance |= VarianceFlagsUnmeasurable
1382+ }
1383+ if c .reliabilityFlags & RelationComparisonResultReportsUnreliable != 0 {
1384+ variance |= VarianceFlagsUnreliable
1385+ }
1386+ c .reliabilityFlags = saveReliabilityFlags
1387+ }
1388+ if len (links .variances ) != 0 {
1389+ break
1390+ }
1391+ variances [i ] = variance
1392+ }
1393+ if len (links .variances ) == 0 {
1394+ links .variances = variances
1395+ }
1396+ c .varianceStack = c .varianceStack [:len (c .varianceStack )- 1 ]
1397+ if len (c .varianceStack ) == 0 {
1398+ c .resolutionStart = saveResolutionStart
1399+ }
14101400 } else {
1411- // We've detected a circularity. Since we may compute different variances depending on where
1412- // we enter a circularity, we find the generic type with the "smallest" symbol in the circular
1413- // region of the variance stack and restart the computation from there if necessary. This
1414- // ensures stable results for circular generic types.
1415- minIndex := stackIndex
1416- for i := stackIndex + 1 ; i < len (c .varianceStack ); i ++ {
1417- if c .compareSymbols (c .varianceStack [i ].symbol , c .varianceStack [minIndex ].symbol ) < 0 {
1418- minIndex = i
1419- }
1420- }
1421- if minIndex > stackIndex {
1422- saveVarianceStack := c .varianceStack
1423- c .varianceStack = nil
1424- c .getVariancesWorker (saveVarianceStack [minIndex ].symbol , saveVarianceStack [minIndex ].typeParameters )
1425- c .varianceStack = saveVarianceStack
1426- }
1427- // Store an empty slice to mark that we can't compute variances for this type. We treat type
1428- // parameters as co-variant in this case.
1429- if len (links .variances ) == 0 {
1430- links .variances = []VarianceFlags {}
1431- }
1432- }
1401+ // Handle circularity without unsafe stack restarts that cause regressions
1402+ // in recursive generic interfaces.
1403+ if len (links .variances ) == 0 {
1404+ links .variances = []VarianceFlags {}
1405+ }
1406+ }
14331407 }
14341408 return links .variances
14351409}
0 commit comments