11// Licensed to the .NET Foundation under one or more agreements.
22// The .NET Foundation licenses this file to you under the MIT license.
33
4+ using System . Collections . Generic ;
45using System . Reflection . Metadata ;
56using System . Reflection . Metadata . Ecma335 ;
67
@@ -14,6 +15,146 @@ internal static partial class LazyGenericsSupport
1415 {
1516 private sealed partial class GraphBuilder
1617 {
18+ // Generate the illegal recursion graph as specified in ECMA 335 II.9.2 Generics and recursive inheritance graphs
19+ public GraphBuilder ( EcmaType type )
20+ {
21+ _graph = new Graph < EcmaGenericParameter > ( ) ;
22+
23+ if ( type . HasInstantiation )
24+ {
25+ HashSet < TypeDesc > types = new HashSet < TypeDesc > ( ) ;
26+ List < TypeDesc > typesToProcess = new List < TypeDesc > ( ) ;
27+ typesToProcess . Add ( type ) ;
28+ while ( typesToProcess . Count > 0 )
29+ {
30+ var processType = typesToProcess [ typesToProcess . Count - 1 ] ;
31+ typesToProcess . RemoveAt ( typesToProcess . Count - 1 ) ;
32+
33+ if ( processType . IsParameterizedType )
34+ {
35+ if ( processType . GetParameterType ( ) is InstantiatedType instantiatedType )
36+ {
37+ AddProcessType ( instantiatedType . GetTypeDefinition ( ) ) ;
38+ WalkFormals ( instantiatedType , expanded : true ) ;
39+ }
40+ }
41+ else if ( processType . GetTypeDefinition ( ) == processType )
42+ {
43+ if ( processType . HasInstantiation && processType is EcmaType ecmaProcessType )
44+ {
45+ AddSpecializedType ( ecmaProcessType . BaseType ) ;
46+ foreach ( var t in ecmaProcessType . ExplicitlyImplementedInterfaces )
47+ {
48+ AddSpecializedType ( t ) ;
49+ }
50+
51+ void AddSpecializedType ( TypeDesc typeToSpecialize )
52+ {
53+ if ( typeToSpecialize != null )
54+ {
55+ var specializedType = typeToSpecialize . InstantiateSignature ( processType . Instantiation , default ( Instantiation ) ) ;
56+ AddProcessType ( specializedType ) ;
57+ }
58+ }
59+ }
60+ }
61+ else if ( processType is InstantiatedType instantiatedType )
62+ {
63+ AddProcessType ( instantiatedType . GetTypeDefinition ( ) ) ;
64+ WalkFormals ( instantiatedType , expanded : false ) ;
65+ }
66+
67+ void WalkFormals ( InstantiatedType instantiatedType , bool expanded )
68+ {
69+ for ( int i = 0 ; i < instantiatedType . Instantiation . Length ; i ++ )
70+ {
71+ var formal = instantiatedType . GetTypeDefinition ( ) . Instantiation [ i ] as GenericParameterDesc ;
72+ if ( instantiatedType . Instantiation [ i ] is GenericParameterDesc genParam )
73+ {
74+ AddEdge ( genParam , formal , expanded ) ;
75+ }
76+ else
77+ {
78+ foreach ( var genParameter in GetGenericParameters ( instantiatedType . Instantiation [ i ] ) )
79+ {
80+ AddEdge ( genParameter , formal , true ) ;
81+ }
82+ }
83+ }
84+ }
85+
86+ void AddProcessType ( TypeDesc type )
87+ {
88+ if ( type == null )
89+ return ;
90+
91+ if ( types . Add ( type ) )
92+ {
93+ typesToProcess . Add ( type ) ;
94+ }
95+
96+ if ( type is ParameterizedType paramType )
97+ {
98+ AddProcessType ( paramType . GetParameterType ( ) ) ;
99+ }
100+
101+ foreach ( var instType in type . Instantiation )
102+ {
103+ AddProcessType ( instType ) ;
104+ }
105+ }
106+
107+ void AddEdge ( GenericParameterDesc from , GenericParameterDesc to , bool flagged )
108+ {
109+ EcmaGenericParameter fromEcma = from as EcmaGenericParameter ;
110+ EcmaGenericParameter toEcma = to as EcmaGenericParameter ;
111+ if ( fromEcma == null || toEcma == null )
112+ return ;
113+ _graph . AddEdge ( fromEcma , toEcma , flagged ) ;
114+ }
115+
116+ IEnumerable < GenericParameterDesc > GetGenericParameters ( TypeDesc t )
117+ {
118+ if ( t is GenericParameterDesc genParamDesc )
119+ {
120+ yield return genParamDesc ;
121+ }
122+ else if ( t is ParameterizedType paramType )
123+ {
124+ foreach ( var genParamType in GetGenericParameters ( paramType . GetParameterType ( ) ) )
125+ {
126+ yield return genParamType ;
127+ }
128+ }
129+ else if ( t . HasInstantiation )
130+ {
131+ foreach ( var instType in t . Instantiation )
132+ {
133+ foreach ( var genParamType in GetGenericParameters ( instType ) )
134+ {
135+ yield return genParamType ;
136+ }
137+ }
138+ }
139+ else if ( t is FunctionPointerType fptrType )
140+ {
141+ foreach ( var genParamType in GetGenericParameters ( fptrType . Signature . ReturnType ) )
142+ {
143+ yield return genParamType ;
144+ }
145+ foreach ( var parameterType in fptrType . Signature )
146+ {
147+ foreach ( var genParamType in GetGenericParameters ( parameterType ) )
148+ {
149+ yield return genParamType ;
150+ }
151+ }
152+ }
153+ }
154+ }
155+ }
156+ }
157+
17158 public GraphBuilder ( EcmaModule assembly )
18159 {
19160 _graph = new Graph < EcmaGenericParameter > ( ) ;
0 commit comments