1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Collections.Generic;
7 using System.Diagnostics;
8 using System.Linq;
9 using System.Reflection;
10 using System.Runtime.CompilerServices;
11 using Microsoft.CSharp.RuntimeBinder.Syntax;
12 
13 namespace Microsoft.CSharp.RuntimeBinder.Semantics
14 {
15     internal sealed class TypeManager
16     {
17         private BSYMMGR _BSymmgr;
18         private PredefinedTypes _predefTypes;
19 
20         private readonly TypeFactory _typeFactory;
21         private readonly TypeTable _typeTable;
22         private SymbolTable _symbolTable;
23 
24         // Special types
25         private readonly VoidType _voidType;
26         private readonly NullType _nullType;
27         private readonly MethodGroupType _typeMethGrp;
28         private readonly ArgumentListType _argListType;
29 
30         private readonly StdTypeVarColl _stvcMethod;
31         private readonly StdTypeVarColl _stvcClass;
32 
TypeManager(BSYMMGR bsymmgr, PredefinedTypes predefTypes)33         public TypeManager(BSYMMGR bsymmgr, PredefinedTypes predefTypes)
34         {
35             _typeFactory = new TypeFactory();
36             _typeTable = new TypeTable();
37 
38             // special types with their own symbol kind.
39             _voidType = _typeFactory.CreateVoid();
40             _nullType = _typeFactory.CreateNull();
41             _typeMethGrp = _typeFactory.CreateMethodGroup();
42             _argListType = _typeFactory.CreateArgList();
43 
44             _stvcMethod = new StdTypeVarColl();
45             _stvcClass = new StdTypeVarColl();
46             _BSymmgr = bsymmgr;
47             _predefTypes = predefTypes;
48         }
49 
InitTypeFactory(SymbolTable table)50         public void InitTypeFactory(SymbolTable table)
51         {
52             _symbolTable = table;
53         }
54 
55         public SymbolTable SymbolTable => _symbolTable;
56 
57         private sealed class StdTypeVarColl
58         {
59             private readonly List<TypeParameterType> prgptvs;
60 
StdTypeVarColl()61             public StdTypeVarColl()
62             {
63                 prgptvs = new List<TypeParameterType>();
64             }
65 
66             ////////////////////////////////////////////////////////////////////////////////
67             // Get the standard type variable (eg, !0, !1, or !!0, !!1).
68             //
69             //      iv is the index.
70             //      pbsm is the containing symbol manager
71             //      fMeth designates whether this is a method type var or class type var
72             //
73             // The standard class type variables are useful during emit, but not for type
74             // comparison when binding. The standard method type variables are useful during
75             // binding for signature comparison.
76 
GetTypeVarSym(int iv, TypeManager pTypeManager, bool fMeth)77             public TypeParameterType GetTypeVarSym(int iv, TypeManager pTypeManager, bool fMeth)
78             {
79                 Debug.Assert(iv >= 0);
80 
81                 TypeParameterType tpt;
82                 if (iv >= this.prgptvs.Count)
83                 {
84                     TypeParameterSymbol pTypeParameter = new TypeParameterSymbol();
85                     pTypeParameter.SetIsMethodTypeParameter(fMeth);
86                     pTypeParameter.SetIndexInOwnParameters(iv);
87                     pTypeParameter.SetIndexInTotalParameters(iv);
88                     pTypeParameter.SetAccess(ACCESS.ACC_PRIVATE);
89                     tpt = pTypeManager.GetTypeParameter(pTypeParameter);
90                     this.prgptvs.Add(tpt);
91                 }
92                 else
93                 {
94                     tpt = this.prgptvs[iv];
95                 }
96                 Debug.Assert(tpt != null);
97                 return tpt;
98             }
99         }
100 
GetArray(CType elementType, int args, bool isSZArray)101         public ArrayType GetArray(CType elementType, int args, bool isSZArray)
102         {
103             Name name;
104 
105             Debug.Assert(args > 0 && args < 32767);
106             Debug.Assert(args == 1 || !isSZArray);
107 
108             switch (args)
109             {
110                 case 1:
111                     if (isSZArray)
112                     {
113                         goto case 2;
114                     }
115                     else
116                     {
117                         goto default;
118                     }
119                 case 2:
120                     name = NameManager.GetPredefinedName(PredefinedName.PN_ARRAY0 + args);
121                     break;
122                 default:
123                     name = NameManager.Add("[X" + args + 1);
124                     break;
125             }
126 
127             // See if we already have an array type of this element type and rank.
128             ArrayType pArray = _typeTable.LookupArray(name, elementType);
129             if (pArray == null)
130             {
131                 // No existing array symbol. Create a new one.
132                 pArray = _typeFactory.CreateArray(name, elementType, args, isSZArray);
133                 _typeTable.InsertArray(name, elementType, pArray);
134             }
135 
136             Debug.Assert(pArray.rank == args);
137             Debug.Assert(pArray.GetElementType() == elementType);
138 
139             return pArray;
140         }
141 
GetAggregate(AggregateSymbol agg, AggregateType atsOuter, TypeArray typeArgs)142         public AggregateType GetAggregate(AggregateSymbol agg, AggregateType atsOuter, TypeArray typeArgs)
143         {
144             Debug.Assert(agg.GetTypeManager() == this);
145             Debug.Assert(atsOuter == null || atsOuter.getAggregate() == agg.Parent, "");
146 
147             if (typeArgs == null)
148             {
149                 typeArgs = BSYMMGR.EmptyTypeArray();
150             }
151 
152             Debug.Assert(agg.GetTypeVars().Count == typeArgs.Count);
153             AggregateType pAggregate = _typeTable.LookupAggregate(agg, atsOuter, typeArgs);
154             if (pAggregate == null)
155             {
156                 pAggregate = _typeFactory.CreateAggregateType(
157                           agg,
158                           typeArgs,
159                           atsOuter
160                       );
161 
162                 Debug.Assert(!pAggregate.fConstraintsChecked && !pAggregate.fConstraintError);
163 
164                 _typeTable.InsertAggregate(agg, atsOuter, typeArgs, pAggregate);
165             }
166 
167             Debug.Assert(pAggregate.getAggregate() == agg);
168             Debug.Assert(pAggregate.GetTypeArgsThis() != null && pAggregate.GetTypeArgsAll() != null);
169             Debug.Assert(pAggregate.GetTypeArgsThis() == typeArgs);
170 
171             return pAggregate;
172         }
173 
GetAggregate(AggregateSymbol agg, TypeArray typeArgsAll)174         public AggregateType GetAggregate(AggregateSymbol agg, TypeArray typeArgsAll)
175         {
176             Debug.Assert(typeArgsAll != null && typeArgsAll.Count == agg.GetTypeVarsAll().Count);
177 
178             if (typeArgsAll.Count == 0)
179                 return agg.getThisType();
180 
181             AggregateSymbol aggOuter = agg.GetOuterAgg();
182 
183             if (aggOuter == null)
184                 return GetAggregate(agg, null, typeArgsAll);
185 
186             int cvarOuter = aggOuter.GetTypeVarsAll().Count;
187             Debug.Assert(cvarOuter <= typeArgsAll.Count);
188 
189             TypeArray typeArgsOuter = _BSymmgr.AllocParams(cvarOuter, typeArgsAll, 0);
190             TypeArray typeArgsInner = _BSymmgr.AllocParams(agg.GetTypeVars().Count, typeArgsAll, cvarOuter);
191             AggregateType atsOuter = GetAggregate(aggOuter, typeArgsOuter);
192 
193             return GetAggregate(agg, atsOuter, typeArgsInner);
194         }
195 
GetPointer(CType baseType)196         public PointerType GetPointer(CType baseType)
197         {
198             PointerType pPointer = _typeTable.LookupPointer(baseType);
199             if (pPointer == null)
200             {
201                 // No existing type. Create a new one.
202                 Name namePtr = NameManager.GetPredefinedName(PredefinedName.PN_PTR);
203 
204                 pPointer = _typeFactory.CreatePointer(namePtr, baseType);
205                 _typeTable.InsertPointer(baseType, pPointer);
206             }
207 
208             Debug.Assert(pPointer.GetReferentType() == baseType);
209 
210             return pPointer;
211         }
212 
GetNullable(CType pUnderlyingType)213         public NullableType GetNullable(CType pUnderlyingType)
214         {
215             if (pUnderlyingType is NullableType nt)
216             {
217                 Debug.Fail("Attempt to make nullable of nullable");
218                 return nt;
219             }
220 
221             NullableType pNullableType = _typeTable.LookupNullable(pUnderlyingType);
222             if (pNullableType == null)
223             {
224                 Name pName = NameManager.GetPredefinedName(PredefinedName.PN_NUB);
225 
226                 pNullableType = _typeFactory.CreateNullable(pName, pUnderlyingType, _BSymmgr, this);
227                 _typeTable.InsertNullable(pUnderlyingType, pNullableType);
228             }
229 
230             return pNullableType;
231         }
232 
GetNubFromNullable(AggregateType ats)233         public NullableType GetNubFromNullable(AggregateType ats)
234         {
235             Debug.Assert(ats.isPredefType(PredefinedType.PT_G_OPTIONAL));
236             return GetNullable(ats.GetTypeArgsAll()[0]);
237         }
238 
GetParameterModifier(CType paramType, bool isOut)239         public ParameterModifierType GetParameterModifier(CType paramType, bool isOut)
240         {
241             Name name = NameManager.GetPredefinedName(isOut ? PredefinedName.PN_OUTPARAM : PredefinedName.PN_REFPARAM);
242             ParameterModifierType pParamModifier = _typeTable.LookupParameterModifier(name, paramType);
243 
244             if (pParamModifier == null)
245             {
246                 // No existing parammod symbol. Create a new one.
247                 pParamModifier = _typeFactory.CreateParameterModifier(name, paramType);
248                 pParamModifier.isOut = isOut;
249                 _typeTable.InsertParameterModifier(name, paramType, pParamModifier);
250             }
251 
252             Debug.Assert(pParamModifier.GetParameterType() == paramType);
253 
254             return pParamModifier;
255         }
256 
GetVoid()257         public VoidType GetVoid()
258         {
259             return _voidType;
260         }
261 
GetNullType()262         public NullType GetNullType()
263         {
264             return _nullType;
265         }
266 
GetMethGrpType()267         public MethodGroupType GetMethGrpType()
268         {
269             return _typeMethGrp;
270         }
271 
GetArgListType()272         public ArgumentListType GetArgListType()
273         {
274             return _argListType;
275         }
276 
GetNullable()277         public AggregateSymbol GetNullable() => GetPredefAgg(PredefinedType.PT_G_OPTIONAL);
278 
SubstType(CType typeSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth, SubstTypeFlags grfst)279         private CType SubstType(CType typeSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth, SubstTypeFlags grfst)
280         {
281             if (typeSrc == null)
282                 return null;
283 
284             var ctx = new SubstContext(typeArgsCls, typeArgsMeth, grfst);
285             return ctx.FNop() ? typeSrc : SubstTypeCore(typeSrc, ctx);
286         }
287 
SubstType(AggregateType typeSrc, TypeArray typeArgsCls)288         public AggregateType SubstType(AggregateType typeSrc, TypeArray typeArgsCls)
289         {
290             if (typeSrc != null)
291             {
292                 SubstContext ctx = new SubstContext(typeArgsCls, null, SubstTypeFlags.NormNone);
293                 if (!ctx.FNop())
294                 {
295                     return SubstTypeCore(typeSrc, ctx);
296                 }
297             }
298 
299             return typeSrc;
300         }
301 
SubstType(CType typeSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth)302         private CType SubstType(CType typeSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth)
303         {
304             return SubstType(typeSrc, typeArgsCls, typeArgsMeth, SubstTypeFlags.NormNone);
305         }
306 
SubstTypeArray(TypeArray taSrc, SubstContext ctx)307         public TypeArray SubstTypeArray(TypeArray taSrc, SubstContext ctx)
308         {
309             if (taSrc != null && taSrc.Count != 0 && ctx != null && !ctx.FNop())
310             {
311                 CType[] srcs = taSrc.Items;
312                 for (int i = 0; i < srcs.Length; i++)
313                 {
314                     CType src = srcs[i];
315                     CType dst = SubstTypeCore(src, ctx);
316                     if (src != dst)
317                     {
318                         CType[] dsts = new CType[srcs.Length];
319                         Array.Copy(srcs, dsts, i);
320                         dsts[i] = dst;
321                         while (++i < srcs.Length)
322                         {
323                             dsts[i] = SubstTypeCore(srcs[i], ctx);
324                         }
325 
326                         return _BSymmgr.AllocParams(dsts);
327                     }
328                 }
329             }
330 
331             return taSrc;
332         }
333 
SubstTypeArray(TypeArray taSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth)334         public TypeArray SubstTypeArray(TypeArray taSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth)
335             => taSrc == null || taSrc.Count == 0
336             ? taSrc
337             : SubstTypeArray(taSrc, new SubstContext(typeArgsCls, typeArgsMeth, SubstTypeFlags.NormNone));
338 
SubstTypeArray(TypeArray taSrc, TypeArray typeArgsCls)339         public TypeArray SubstTypeArray(TypeArray taSrc, TypeArray typeArgsCls) => SubstTypeArray(taSrc, typeArgsCls, null);
340 
SubstTypeCore(AggregateType type, SubstContext ctx)341         private AggregateType SubstTypeCore(AggregateType type, SubstContext ctx)
342         {
343             TypeArray args = type.GetTypeArgsAll();
344             if (args.Count > 0)
345             {
346                 TypeArray typeArgs = SubstTypeArray(args, ctx);
347                 if (args != typeArgs)
348                 {
349                     return GetAggregate(type.getAggregate(), typeArgs);
350                 }
351             }
352 
353             return type;
354         }
355 
SubstTypeCore(CType type, SubstContext pctx)356         private CType SubstTypeCore(CType type, SubstContext pctx)
357         {
358             CType typeSrc;
359             CType typeDst;
360 
361             switch (type.GetTypeKind())
362             {
363                 default:
364                     Debug.Assert(false);
365                     return type;
366 
367                 case TypeKind.TK_NullType:
368                 case TypeKind.TK_VoidType:
369                 case TypeKind.TK_MethodGroupType:
370                 case TypeKind.TK_ArgumentListType:
371                     return type;
372 
373                 case TypeKind.TK_ParameterModifierType:
374                     ParameterModifierType mod = (ParameterModifierType)type;
375                     typeDst = SubstTypeCore(typeSrc = mod.GetParameterType(), pctx);
376                     return (typeDst == typeSrc) ? type : GetParameterModifier(typeDst, mod.isOut);
377 
378                 case TypeKind.TK_ArrayType:
379                     var arr = (ArrayType)type;
380                     typeDst = SubstTypeCore(typeSrc = arr.GetElementType(), pctx);
381                     return (typeDst == typeSrc) ? type : GetArray(typeDst, arr.rank, arr.IsSZArray);
382 
383                 case TypeKind.TK_PointerType:
384                     typeDst = SubstTypeCore(typeSrc = ((PointerType)type).GetReferentType(), pctx);
385                     return (typeDst == typeSrc) ? type : GetPointer(typeDst);
386 
387                 case TypeKind.TK_NullableType:
388                     typeDst = SubstTypeCore(typeSrc = ((NullableType)type).GetUnderlyingType(), pctx);
389                     return (typeDst == typeSrc) ? type : GetNullable(typeDst);
390 
391                 case TypeKind.TK_AggregateType:
392                     return SubstTypeCore((AggregateType)type, pctx);
393 
394                 case TypeKind.TK_TypeParameterType:
395                     {
396                         TypeParameterSymbol tvs = ((TypeParameterType)type).GetTypeParameterSymbol();
397                         int index = tvs.GetIndexInTotalParameters();
398                         if (tvs.IsMethodTypeParameter())
399                         {
400                             if ((pctx.grfst & SubstTypeFlags.DenormMeth) != 0 && tvs.parent != null)
401                                 return type;
402                             Debug.Assert(tvs.GetIndexInOwnParameters() == tvs.GetIndexInTotalParameters());
403                             if (index < pctx.ctypeMeth)
404                             {
405                                 Debug.Assert(pctx.prgtypeMeth != null);
406                                 return pctx.prgtypeMeth[index];
407                             }
408                             else
409                             {
410                                 return ((pctx.grfst & SubstTypeFlags.NormMeth) != 0 ? GetStdMethTypeVar(index) : type);
411                             }
412                         }
413                         if ((pctx.grfst & SubstTypeFlags.DenormClass) != 0 && tvs.parent != null)
414                             return type;
415                         return index < pctx.ctypeCls ? pctx.prgtypeCls[index] :
416                                ((pctx.grfst & SubstTypeFlags.NormClass) != 0 ? GetStdClsTypeVar(index) : type);
417                     }
418             }
419         }
420 
SubstEqualTypes(CType typeDst, CType typeSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth, SubstTypeFlags grfst)421         public bool SubstEqualTypes(CType typeDst, CType typeSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth, SubstTypeFlags grfst)
422         {
423             if (typeDst.Equals(typeSrc))
424             {
425                 Debug.Assert(typeDst.Equals(SubstType(typeSrc, typeArgsCls, typeArgsMeth, grfst)));
426                 return true;
427             }
428 
429             var ctx = new SubstContext(typeArgsCls, typeArgsMeth, grfst);
430 
431             return !ctx.FNop() && SubstEqualTypesCore(typeDst, typeSrc, ctx);
432         }
433 
SubstEqualTypeArrays(TypeArray taDst, TypeArray taSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth, SubstTypeFlags grfst)434         public bool SubstEqualTypeArrays(TypeArray taDst, TypeArray taSrc, TypeArray typeArgsCls, TypeArray typeArgsMeth, SubstTypeFlags grfst)
435         {
436             // Handle the simple common cases first.
437             if (taDst == taSrc || (taDst != null && taDst.Equals(taSrc)))
438             {
439                 // The following assertion is not always true and indicates a problem where
440                 // the signature of override method does not match the one inherited from
441                 // the base class. The method match we have found does not take the type
442                 // arguments of the base class into account. So actually we are not overriding
443                 // the method that we "intend" to.
444                 // Debug.Assert(taDst == SubstTypeArray(taSrc, typeArgsCls, typeArgsMeth, grfst));
445                 return true;
446             }
447             if (taDst.Count != taSrc.Count)
448                 return false;
449             if (taDst.Count == 0)
450                 return true;
451 
452             var ctx = new SubstContext(typeArgsCls, typeArgsMeth, grfst);
453 
454             if (ctx.FNop())
455                 return false;
456 
457             for (int i = 0; i < taDst.Count; i++)
458             {
459                 if (!SubstEqualTypesCore(taDst[i], taSrc[i], ctx))
460                     return false;
461             }
462 
463             return true;
464         }
465 
SubstEqualTypesCore(CType typeDst, CType typeSrc, SubstContext pctx)466         private bool SubstEqualTypesCore(CType typeDst, CType typeSrc, SubstContext pctx)
467         {
468         LRecurse:  // Label used for "tail" recursion.
469 
470             if (typeDst == typeSrc || typeDst.Equals(typeSrc))
471             {
472                 return true;
473             }
474 
475             switch (typeSrc.GetTypeKind())
476             {
477                 default:
478                     Debug.Assert(false, "Bad Symbol kind in SubstEqualTypesCore");
479                     return false;
480 
481                 case TypeKind.TK_NullType:
482                 case TypeKind.TK_VoidType:
483                     // There should only be a single instance of these.
484                     Debug.Assert(typeDst.GetTypeKind() != typeSrc.GetTypeKind());
485                     return false;
486 
487                 case TypeKind.TK_ArrayType:
488                     ArrayType arrSrc = (ArrayType)typeSrc;
489                     if (!(typeDst is ArrayType arrDst) || arrDst.rank != arrSrc.rank || arrDst.IsSZArray != arrSrc.IsSZArray)
490                         return false;
491                     goto LCheckBases;
492 
493                 case TypeKind.TK_ParameterModifierType:
494                     if (!(typeDst is ParameterModifierType modDest) ||
495                         ((pctx.grfst & SubstTypeFlags.NoRefOutDifference) == 0 &&
496                          modDest.isOut != ((ParameterModifierType)typeSrc).isOut))
497                         return false;
498                     goto LCheckBases;
499 
500                 case TypeKind.TK_PointerType:
501                 case TypeKind.TK_NullableType:
502                     if (typeDst.GetTypeKind() != typeSrc.GetTypeKind())
503                         return false;
504                     LCheckBases:
505                     typeSrc = typeSrc.GetBaseOrParameterOrElementType();
506                     typeDst = typeDst.GetBaseOrParameterOrElementType();
507                     goto LRecurse;
508 
509                 case TypeKind.TK_AggregateType:
510                     if (!(typeDst is AggregateType atsDst))
511                         return false;
512                     { // BLOCK
513                         AggregateType atsSrc = (AggregateType)typeSrc;
514 
515                         if (atsSrc.getAggregate() != atsDst.getAggregate())
516                             return false;
517 
518                         Debug.Assert(atsSrc.GetTypeArgsAll().Count == atsDst.GetTypeArgsAll().Count);
519 
520                         // All the args must unify.
521                         for (int i = 0; i < atsSrc.GetTypeArgsAll().Count; i++)
522                         {
523                             if (!SubstEqualTypesCore(atsDst.GetTypeArgsAll()[i], atsSrc.GetTypeArgsAll()[i], pctx))
524                                 return false;
525                         }
526                     }
527                     return true;
528 
529                 case TypeKind.TK_TypeParameterType:
530                     { // BLOCK
531                         TypeParameterSymbol tvs = ((TypeParameterType)typeSrc).GetTypeParameterSymbol();
532                         int index = tvs.GetIndexInTotalParameters();
533 
534                         if (tvs.IsMethodTypeParameter())
535                         {
536                             if ((pctx.grfst & SubstTypeFlags.DenormMeth) != 0 && tvs.parent != null)
537                             {
538                                 // typeDst == typeSrc was handled above.
539                                 Debug.Assert(typeDst != typeSrc);
540                                 return false;
541                             }
542                             Debug.Assert(tvs.GetIndexInOwnParameters() == tvs.GetIndexInTotalParameters());
543                             Debug.Assert(pctx.prgtypeMeth == null || tvs.GetIndexInTotalParameters() < pctx.ctypeMeth);
544                             if (index < pctx.ctypeMeth && pctx.prgtypeMeth != null)
545                             {
546                                 return typeDst == pctx.prgtypeMeth[index];
547                             }
548                             if ((pctx.grfst & SubstTypeFlags.NormMeth) != 0)
549                             {
550                                 return typeDst == GetStdMethTypeVar(index);
551                             }
552                         }
553                         else
554                         {
555                             if ((pctx.grfst & SubstTypeFlags.DenormClass) != 0 && tvs.parent != null)
556                             {
557                                 // typeDst == typeSrc was handled above.
558                                 Debug.Assert(typeDst != typeSrc);
559                                 return false;
560                             }
561                             Debug.Assert(pctx.prgtypeCls == null || tvs.GetIndexInTotalParameters() < pctx.ctypeCls);
562                             if (index < pctx.ctypeCls)
563                                 return typeDst == pctx.prgtypeCls[index];
564                             if ((pctx.grfst & SubstTypeFlags.NormClass) != 0)
565                                 return typeDst == GetStdClsTypeVar(index);
566                         }
567                     }
568                     return false;
569             }
570         }
571 
TypeContainsType(CType type, CType typeFind)572         public static bool TypeContainsType(CType type, CType typeFind)
573         {
574         LRecurse:  // Label used for "tail" recursion.
575 
576             if (type == typeFind || type.Equals(typeFind))
577                 return true;
578 
579             switch (type.GetTypeKind())
580             {
581                 default:
582                     Debug.Assert(false, "Bad Symbol kind in TypeContainsType");
583                     return false;
584 
585                 case TypeKind.TK_NullType:
586                 case TypeKind.TK_VoidType:
587                     // There should only be a single instance of these.
588                     Debug.Assert(typeFind.GetTypeKind() != type.GetTypeKind());
589                     return false;
590 
591                 case TypeKind.TK_ArrayType:
592                 case TypeKind.TK_NullableType:
593                 case TypeKind.TK_ParameterModifierType:
594                 case TypeKind.TK_PointerType:
595                     type = type.GetBaseOrParameterOrElementType();
596                     goto LRecurse;
597 
598                 case TypeKind.TK_AggregateType:
599                     { // BLOCK
600                         AggregateType ats = (AggregateType)type;
601 
602                         for (int i = 0; i < ats.GetTypeArgsAll().Count; i++)
603                         {
604                             if (TypeContainsType(ats.GetTypeArgsAll()[i], typeFind))
605                                 return true;
606                         }
607                     }
608                     return false;
609 
610                 case TypeKind.TK_TypeParameterType:
611                     return false;
612             }
613         }
614 
TypeContainsTyVars(CType type, TypeArray typeVars)615         public static bool TypeContainsTyVars(CType type, TypeArray typeVars)
616         {
617         LRecurse:  // Label used for "tail" recursion.
618             switch (type.GetTypeKind())
619             {
620                 default:
621                     Debug.Assert(false, "Bad Symbol kind in TypeContainsTyVars");
622                     return false;
623 
624                 case TypeKind.TK_NullType:
625                 case TypeKind.TK_VoidType:
626                 case TypeKind.TK_MethodGroupType:
627                     return false;
628 
629                 case TypeKind.TK_ArrayType:
630                 case TypeKind.TK_NullableType:
631                 case TypeKind.TK_ParameterModifierType:
632                 case TypeKind.TK_PointerType:
633                     type = type.GetBaseOrParameterOrElementType();
634                     goto LRecurse;
635 
636                 case TypeKind.TK_AggregateType:
637                     { // BLOCK
638                         AggregateType ats = (AggregateType)type;
639 
640                         for (int i = 0; i < ats.GetTypeArgsAll().Count; i++)
641                         {
642                             if (TypeContainsTyVars(ats.GetTypeArgsAll()[i], typeVars))
643                             {
644                                 return true;
645                             }
646                         }
647                     }
648                     return false;
649 
650                 case TypeKind.TK_TypeParameterType:
651                     if (typeVars != null && typeVars.Count > 0)
652                     {
653                         int ivar = ((TypeParameterType)type).GetIndexInTotalParameters();
654                         return ivar < typeVars.Count && type == typeVars[ivar];
655                     }
656                     return true;
657             }
658         }
659 
660         public static bool ParametersContainTyVar(TypeArray @params, TypeParameterType typeFind)
661         {
662             Debug.Assert(@params != null);
663             Debug.Assert(typeFind != null);
664             for (int p = 0; p < @params.Count; p++)
665             {
666                 CType sym = @params[p];
667                 if (TypeContainsType(sym, typeFind))
668                 {
669                     return true;
670                 }
671             }
672             return false;
673         }
674 
675         public AggregateSymbol GetPredefAgg(PredefinedType pt) => _predefTypes.GetPredefinedAggregate(pt);
676 
ConcatenateTypeArrays(TypeArray pTypeArray1, TypeArray pTypeArray2)677         public TypeArray ConcatenateTypeArrays(TypeArray pTypeArray1, TypeArray pTypeArray2)
678         {
679             return _BSymmgr.ConcatParams(pTypeArray1, pTypeArray2);
680         }
681 
GetStdMethTyVarArray(int cTyVars)682         public TypeArray GetStdMethTyVarArray(int cTyVars)
683         {
684             TypeParameterType[] prgvar = new TypeParameterType[cTyVars];
685 
686             for (int ivar = 0; ivar < cTyVars; ivar++)
687             {
688                 prgvar[ivar] = GetStdMethTypeVar(ivar);
689             }
690 
691             return _BSymmgr.AllocParams(cTyVars, (CType[])prgvar);
692         }
693 
SubstType(AggregateType typeSrc, SubstContext ctx)694         public AggregateType SubstType(AggregateType typeSrc, SubstContext ctx) =>
695             ctx == null || ctx.FNop() ? typeSrc : SubstTypeCore(typeSrc, ctx);
696 
SubstType(CType typeSrc, SubstContext pctx)697         public CType SubstType(CType typeSrc, SubstContext pctx)
698         {
699             return (pctx == null || pctx.FNop()) ? typeSrc : SubstTypeCore(typeSrc, pctx);
700         }
701 
SubstType(CType typeSrc, AggregateType atsCls)702         public CType SubstType(CType typeSrc, AggregateType atsCls)
703         {
704             return SubstType(typeSrc, atsCls, (TypeArray)null);
705         }
706 
SubstType(CType typeSrc, AggregateType atsCls, TypeArray typeArgsMeth)707         public CType SubstType(CType typeSrc, AggregateType atsCls, TypeArray typeArgsMeth)
708         {
709             return SubstType(typeSrc, atsCls?.GetTypeArgsAll(), typeArgsMeth);
710         }
711 
SubstType(CType typeSrc, CType typeCls, TypeArray typeArgsMeth)712         public CType SubstType(CType typeSrc, CType typeCls, TypeArray typeArgsMeth)
713         {
714             return SubstType(typeSrc, (typeCls as AggregateType)?.GetTypeArgsAll(), typeArgsMeth);
715         }
716 
SubstTypeArray(TypeArray taSrc, AggregateType atsCls, TypeArray typeArgsMeth)717         public TypeArray SubstTypeArray(TypeArray taSrc, AggregateType atsCls, TypeArray typeArgsMeth)
718         {
719             return SubstTypeArray(taSrc, atsCls?.GetTypeArgsAll(), typeArgsMeth);
720         }
721 
SubstTypeArray(TypeArray taSrc, AggregateType atsCls)722         public TypeArray SubstTypeArray(TypeArray taSrc, AggregateType atsCls)
723         {
724             return this.SubstTypeArray(taSrc, atsCls, (TypeArray)null);
725         }
726 
SubstEqualTypes(CType typeDst, CType typeSrc, CType typeCls, TypeArray typeArgsMeth)727         private bool SubstEqualTypes(CType typeDst, CType typeSrc, CType typeCls, TypeArray typeArgsMeth)
728         {
729             return SubstEqualTypes(typeDst, typeSrc, (typeCls as AggregateType)?.GetTypeArgsAll(), typeArgsMeth, SubstTypeFlags.NormNone);
730         }
731 
SubstEqualTypes(CType typeDst, CType typeSrc, CType typeCls)732         public bool SubstEqualTypes(CType typeDst, CType typeSrc, CType typeCls)
733         {
734             return SubstEqualTypes(typeDst, typeSrc, typeCls, (TypeArray)null);
735         }
736 
737         //public bool SubstEqualTypeArrays(TypeArray taDst, TypeArray taSrc, AggregateType atsCls, TypeArray typeArgsMeth)
738         //{
739         //    return SubstEqualTypeArrays(taDst, taSrc, atsCls != null ? atsCls.GetTypeArgsAll() : (TypeArray)null, typeArgsMeth, SubstTypeFlags.NormNone);
740         //}
741 
GetStdMethTypeVar(int iv)742         public TypeParameterType GetStdMethTypeVar(int iv)
743         {
744             return _stvcMethod.GetTypeVarSym(iv, this, true);
745         }
746 
GetStdClsTypeVar(int iv)747         private TypeParameterType GetStdClsTypeVar(int iv)
748         {
749             return _stvcClass.GetTypeVarSym(iv, this, false);
750         }
751 
752         // These are singletons for each.
GetTypeParameter(TypeParameterSymbol pSymbol)753         public TypeParameterType GetTypeParameter(TypeParameterSymbol pSymbol)
754         {
755             Debug.Assert(pSymbol.GetTypeParameterType() == null); // Should have been checked first before creating
756             return _typeFactory.CreateTypeParameter(pSymbol);
757         }
758 
759         // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
760         // RUNTIME BINDER ONLY CHANGE
761         // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
762 
GetBestAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, CType typeSrc, out CType typeDst)763         internal bool GetBestAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, CType typeSrc, out CType typeDst)
764         {
765             // This method implements the "best accessible type" algorithm for determining the type
766             // of untyped arguments in the runtime binder. It is also used in method type inference
767             // to fix type arguments to types that are accessible.
768 
769             // The new type is returned in an out parameter. The result will be true (and the out param
770             // non-null) only when the algorithm could find a suitable accessible type.
771 
772             Debug.Assert(semanticChecker != null);
773             Debug.Assert(bindingContext != null);
774             Debug.Assert(typeSrc != null);
775 
776             typeDst = null;
777 
778             if (semanticChecker.CheckTypeAccess(typeSrc, bindingContext.ContextForMemberLookup))
779             {
780                 // If we already have an accessible type, then use it. This is the terminal point of the recursion.
781                 typeDst = typeSrc;
782                 return true;
783             }
784 
785             // These guys have no accessibility concerns.
786             Debug.Assert(!(typeSrc is VoidType) && !(typeSrc is TypeParameterType));
787 
788             if (typeSrc is ParameterModifierType || typeSrc is PointerType)
789             {
790                 // We cannot vary these.
791                 return false;
792             }
793 
794             CType intermediateType;
795             if (typeSrc is AggregateType aggSrc && (aggSrc.isInterfaceType() || aggSrc.isDelegateType()) && TryVarianceAdjustmentToGetAccessibleType(semanticChecker, bindingContext, aggSrc, out intermediateType))
796             {
797                 // If we have an interface or delegate type, then it can potentially be varied by its type arguments
798                 // to produce an accessible type, and if that's the case, then return that.
799                 // Example: IEnumerable<PrivateConcreteFoo> --> IEnumerable<PublicAbstractFoo>
800                 typeDst = intermediateType;
801 
802                 Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
803                 return true;
804             }
805 
806             if (typeSrc is ArrayType arrSrc && TryArrayVarianceAdjustmentToGetAccessibleType(semanticChecker, bindingContext, arrSrc, out intermediateType))
807             {
808                 // Similarly to the interface and delegate case, arrays are covariant in their element type and
809                 // so we can potentially produce an array type that is accessible.
810                 // Example: PrivateConcreteFoo[] --> PublicAbstractFoo[]
811                 typeDst = intermediateType;
812 
813                 Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
814                 return true;
815             }
816 
817             if (typeSrc is NullableType)
818             {
819                 // We have an inaccessible nullable type, which means that the best we can do is System.ValueType.
820                 typeDst = GetPredefAgg(PredefinedType.PT_VALUE).getThisType();
821 
822                 Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
823                 return true;
824             }
825 
826             if (typeSrc is ArrayType)
827             {
828                 // We have an inaccessible array type for which we could not earlier find a better array type
829                 // with a covariant conversion, so the best we can do is System.Array.
830                 typeDst = GetPredefAgg(PredefinedType.PT_ARRAY).getThisType();
831 
832                 Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
833                 return true;
834             }
835 
836             Debug.Assert(typeSrc is AggregateType);
837 
838             if (typeSrc is AggregateType aggType)
839             {
840                 // We have an AggregateType, so recurse on its base class.
841                 AggregateType baseType = aggType.GetBaseClass();
842 
843                 if (baseType == null)
844                 {
845                     // This happens with interfaces, for instance. But in that case, the
846                     // conversion to object does exist, is an implicit reference conversion,
847                     // and so we will use it.
848                     baseType = GetPredefAgg(PredefinedType.PT_OBJECT).getThisType();
849                 }
850 
851                 return GetBestAccessibleType(semanticChecker, bindingContext, baseType, out typeDst);
852             }
853 
854             return false;
855         }
856 
TryVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, AggregateType typeSrc, out CType typeDst)857         private bool TryVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, AggregateType typeSrc, out CType typeDst)
858         {
859             Debug.Assert(typeSrc != null);
860             Debug.Assert(typeSrc.isInterfaceType() || typeSrc.isDelegateType());
861 
862             typeDst = null;
863 
864             AggregateSymbol aggSym = typeSrc.GetOwningAggregate();
865             AggregateType aggOpenType = aggSym.getThisType();
866 
867             if (!semanticChecker.CheckTypeAccess(aggOpenType, bindingContext.ContextForMemberLookup))
868             {
869                 // if the aggregate symbol itself is not accessible, then forget it, there is no
870                 // variance that will help us arrive at an accessible type.
871                 return false;
872             }
873 
874             TypeArray typeArgs = typeSrc.GetTypeArgsThis();
875             TypeArray typeParams = aggOpenType.GetTypeArgsThis();
876             CType[] newTypeArgsTemp = new CType[typeArgs.Count];
877 
878             for (int i = 0; i < typeArgs.Count; i++)
879             {
880                 if (semanticChecker.CheckTypeAccess(typeArgs[i], bindingContext.ContextForMemberLookup))
881                 {
882                     // we have an accessible argument, this position is not a problem.
883                     newTypeArgsTemp[i] = typeArgs[i];
884                     continue;
885                 }
886 
887                 if (!typeArgs[i].IsRefType() || !((TypeParameterType)typeParams[i]).Covariant)
888                 {
889                     // This guy is inaccessible, and we are not going to be able to vary him, so we need to fail.
890                     return false;
891                 }
892 
893                 CType intermediateTypeArg;
894                 if (GetBestAccessibleType(semanticChecker, bindingContext, typeArgs[i], out intermediateTypeArg))
895                 {
896                     // now we either have a value type (which must be accessible due to the above
897                     // check, OR we have an inaccessible type (which must be a ref type). In either
898                     // case, the recursion worked out and we are OK to vary this argument.
899                     newTypeArgsTemp[i] = intermediateTypeArg;
900                     continue;
901                 }
902                 else
903                 {
904                     Debug.Assert(false, "GetBestAccessibleType unexpectedly failed on a type that was used as a type parameter");
905                     return false;
906                 }
907             }
908 
909             TypeArray newTypeArgs = semanticChecker.getBSymmgr().AllocParams(typeArgs.Count, newTypeArgsTemp);
910             CType intermediateType = this.GetAggregate(aggSym, typeSrc.outerType, newTypeArgs);
911 
912             // All type arguments were varied successfully, which means now we must be accessible. But we could
913             // have violated constraints. Let's check that out.
914 
915             if (!TypeBind.CheckConstraints(semanticChecker, null/*ErrorHandling*/, intermediateType, CheckConstraintsFlags.NoErrors))
916             {
917                 return false;
918             }
919 
920             typeDst = intermediateType;
921             Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
922             return true;
923         }
924 
TryArrayVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, ArrayType typeSrc, out CType typeDst)925         private bool TryArrayVarianceAdjustmentToGetAccessibleType(CSemanticChecker semanticChecker, BindingContext bindingContext, ArrayType typeSrc, out CType typeDst)
926         {
927             Debug.Assert(typeSrc != null);
928 
929             typeDst = null;
930 
931             // We are here because we have an array type with an inaccessible element type. If possible,
932             // we should create a new array type that has an accessible element type for which a
933             // conversion exists.
934 
935             CType elementType = typeSrc.GetElementType();
936             if (!elementType.IsRefType())
937             {
938                 // Covariant array conversions exist for reference types only.
939                 return false;
940             }
941 
942             CType intermediateType;
943             if (GetBestAccessibleType(semanticChecker, bindingContext, elementType, out intermediateType))
944             {
945                 typeDst = this.GetArray(intermediateType, typeSrc.rank, typeSrc.IsSZArray);
946 
947                 Debug.Assert(semanticChecker.CheckTypeAccess(typeDst, bindingContext.ContextForMemberLookup));
948                 return true;
949             }
950 
951             return false;
952         }
953 
954         public AggregateType ObjectAggregateType => (AggregateType)_symbolTable.GetCTypeFromType(typeof(object));
955 
956         private readonly Dictionary<Tuple<Assembly, Assembly>, bool> _internalsVisibleToCalculated
957             = new Dictionary<Tuple<Assembly, Assembly>, bool>();
958 
InternalsVisibleTo(Assembly assemblyThatDefinesAttribute, Assembly assemblyToCheck)959         internal bool InternalsVisibleTo(Assembly assemblyThatDefinesAttribute, Assembly assemblyToCheck)
960         {
961             bool result;
962 
963             var key = Tuple.Create(assemblyThatDefinesAttribute, assemblyToCheck);
964             if (!_internalsVisibleToCalculated.TryGetValue(key, out result))
965             {
966                 AssemblyName assyName;
967 
968                 // Assembly.GetName() requires FileIOPermission to FileIOPermissionAccess.PathDiscovery.
969                 // If we don't have that (we're in low trust), then we are going to effectively turn off
970                 // InternalsVisibleTo. The alternative is to crash when this happens.
971 
972                 try
973                 {
974                     assyName = assemblyToCheck.GetName();
975                 }
976                 catch (System.Security.SecurityException)
977                 {
978                     result = false;
979                     goto SetMemo;
980                 }
981 
982                 result = assemblyThatDefinesAttribute.GetCustomAttributes()
983                     .OfType<InternalsVisibleToAttribute>()
984                     .Select(ivta => new AssemblyName(ivta.AssemblyName))
985                     .Any(an => AssemblyName.ReferenceMatchesDefinition(an, assyName));
986 
987             SetMemo:
988                 _internalsVisibleToCalculated[key] = result;
989             }
990 
991             return result;
992         }
993         // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
994         // END RUNTIME BINDER ONLY CHANGE
995         // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
996     }
997 }
998