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