From baf194e7456ba4568dcf11249896af35b3ce18cc Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Wed, 11 Apr 2018 16:18:29 -0700 Subject: Introduce an IR-level type system (#481) * Introduce an IR-level type system Up to this point, the Slang IR has used the front-end type system to represent types in the IR. As a result (but ultimately more importantly) the IR representation of generics and specialization has used AST-level concepts embedded in the IR. For example, to express the specialization of `vector` to a concrete type `float` for `T`, we needed an IR operation that could represent the specialization, with operands that somehow represented the type argument `float`. The whole thing was very complicated. The big idea of this change is to introduce a new representation in which types in the IR are just ordinary instructions, so that using them as operands makes sense. The hierarchy of IR types closely mirrors the AST-side hierarchy for now, and that will probably be something we should maintain going forward. In order to make these changes work, though, I also had to do major overhauls of things like the way substitutions are performed, how we check interface conformances, the way lookup through interface types is done, etc. etc. This is a big change, and unfortunately any attempt to summarize it in the commit message wouldn't do it justice. * Fix 64-bit build warning * Fix up some clang warnings/errors --- source/slang/syntax.cpp | 1270 +++++++++++++++++++++++++++++------------------ 1 file changed, 792 insertions(+), 478 deletions(-) (limited to 'source/slang/syntax.cpp') diff --git a/source/slang/syntax.cpp b/source/slang/syntax.cpp index 70e230f33..9d29e7d21 100644 --- a/source/slang/syntax.cpp +++ b/source/slang/syntax.cpp @@ -228,12 +228,6 @@ void Type::accept(IValVisitor* visitor, void* extra) overloadedType = new OverloadGroupType(); overloadedType->setSession(this); - - irBasicBlockType = new IRBasicBlockType(); - irBasicBlockType->setSession(this); - - constExprRate = new ConstExprRate(); - constExprRate->setSession(this); } Type* Session::getBoolType() @@ -286,33 +280,12 @@ void Type::accept(IValVisitor* visitor, void* extra) return errorType; } - Type* Session::getIRBasicBlockType() - { - return irBasicBlockType; - } - - Type* Session::getConstExprRate() - { - return constExprRate; - } - Type* Session::getStringType() { auto stringTypeDecl = findMagicDecl(this, "StringType"); return DeclRefType::Create(this, makeDeclRef(stringTypeDecl)); } - RefPtr Session::getRateQualifiedType( - Type* rate, - Type* valueType) - { - RefPtr rateQualifiedType = new RateQualifiedType(); - rateQualifiedType->setSession(this); - rateQualifiedType->rate = rate; - rateQualifiedType->valueType = valueType; - return rateQualifiedType; - } - RefPtr Session::getPtrType( RefPtr valueType) { @@ -363,16 +336,6 @@ void Type::accept(IValVisitor* visitor, void* extra) return arrayType; } - - RefPtr Session::getGroupSharedType(RefPtr valueType) - { - RefPtr groupSharedType = new GroupSharedType(); - groupSharedType->setSession(this); - groupSharedType->valueType = valueType; - return groupSharedType; - } - - SyntaxClass Session::findSyntaxClass(Name* name) { SyntaxClass syntaxClass; @@ -432,142 +395,147 @@ void Type::accept(IValVisitor* visitor, void* extra) return baseType->ToString() + "[]"; } - // RateQualifiedType - - Slang::String RateQualifiedType::ToString() - { - return "@" + rate->ToString() + " " + valueType->ToString(); - } - - bool RateQualifiedType::EqualsImpl(Type * type) - { - auto rateQualifiedType = type->As(); - if(!rateQualifiedType) - return false; - - return rate->Equals(rateQualifiedType->rate) - && valueType->Equals(rateQualifiedType->valueType); - } - - RefPtr RateQualifiedType::SubstituteImpl(SubstitutionSet subst, int* ioDiff) - { - int diff = 0; - auto substRate = rate->SubstituteImpl(subst, &diff).As(); - auto substValueType = valueType->SubstituteImpl(subst, &diff).As(); - if(!diff) - return this; - - (*ioDiff)++; - - return getSession()->getRateQualifiedType(substRate, substValueType); - } - - RefPtr RateQualifiedType::CreateCanonicalType() - { - RefPtr canRate = rate->GetCanonicalType(); - RefPtr canValueType = valueType->GetCanonicalType(); - - RefPtr canRateQualifiedType = new RateQualifiedType(); - canRateQualifiedType->setSession(session); - canRateQualifiedType->rate = canRate; - canRateQualifiedType->valueType = valueType; - return canRateQualifiedType; - } + // DeclRefType - int RateQualifiedType::GetHashCode() + String DeclRefType::ToString() { - auto hash = (int)(typeid(this).hash_code()); - hash = combineHash(hash, rate->GetHashCode()); - hash = combineHash(hash, valueType->GetHashCode()); - return hash; + return declRef.toString(); } - // ConstExprRate - - Slang::String ConstExprRate::ToString() + int DeclRefType::GetHashCode() { - return "ConstExpr"; + return (declRef.GetHashCode() * 16777619) ^ (int)(typeid(this).hash_code()); } - bool ConstExprRate::EqualsImpl(Type * type) + bool DeclRefType::EqualsImpl(Type * type) { - auto constExprRate = type->As(); - if(!constExprRate) - return false; - - return true; + if (auto declRefType = type->AsDeclRefType()) + { + return declRef.Equals(declRefType->declRef); + } + return false; } - RefPtr ConstExprRate::SubstituteImpl(SubstitutionSet /*subst*/, int* /*ioDiff*/) + RefPtr DeclRefType::CreateCanonicalType() { + // A declaration reference is already canonical return this; } - RefPtr ConstExprRate::CreateCanonicalType() - { - return this; - } + // + // RequirementWitness + // - int ConstExprRate::GetHashCode() - { - auto hash = (int)(typeid(this).hash_code()); - return hash; - } + RequirementWitness::RequirementWitness(RefPtr val) + : m_flavor(Flavor::val) + , m_obj(val) + {} - // GroupSharedType - Slang::String GroupSharedType::ToString() - { - return "@ThreadGroup " + valueType->ToString(); - } + RequirementWitness::RequirementWitness(RefPtr witnessTable) + : m_flavor(Flavor::witnessTable) + , m_obj(witnessTable) + {} - bool GroupSharedType::EqualsImpl(Type * type) + RefPtr RequirementWitness::getWitnessTable() { - auto t = type->As(); - if (!t) - return false; - return valueType->Equals(t->valueType); + SLANG_ASSERT(getFlavor() == Flavor::witnessTable); + return m_obj.As(); } - RefPtr GroupSharedType::CreateCanonicalType() - { - auto canonicalValueType = valueType->GetCanonicalType(); - auto canonicalGroupSharedType = getSession()->getGroupSharedType(canonicalValueType); - return canonicalGroupSharedType; - } - int GroupSharedType::GetHashCode() + RequirementWitness RequirementWitness::specialize(SubstitutionSet const& subst) { - return combineHash( - valueType->GetHashCode(), - (int)(typeid(this).hash_code())); - } - - // DeclRefType + switch(getFlavor()) + { + default: + SLANG_UNEXPECTED("unknown requirement witness flavor"); + case RequirementWitness::Flavor::none: + return RequirementWitness(); - String DeclRefType::ToString() - { - return declRef.toString(); - } + case RequirementWitness::Flavor::declRef: + { + int diff = 0; + return RequirementWitness( + getDeclRef().SubstituteImpl(subst, &diff)); + } - int DeclRefType::GetHashCode() - { - return (declRef.GetHashCode() * 16777619) ^ (int)(typeid(this).hash_code()); + case RequirementWitness::Flavor::val: + return RequirementWitness( + getVal()->Substitute(subst)); + } } - bool DeclRefType::EqualsImpl(Type * type) + RequirementWitness tryLookUpRequirementWitness( + SubtypeWitness* subtypeWitness, + Decl* requirementKey) { - if (auto declRefType = type->AsDeclRefType()) + if(auto declaredSubtypeWitness = dynamic_cast(subtypeWitness)) { - return declRef.Equals(declRefType->declRef); + if(auto inheritanceDeclRef = declaredSubtypeWitness->declRef.As()) + { + // A conformance that was declared as part of an inheritance clause + // will have built up a dictionary of the satisfying declarations + // for each of its requirements. + RequirementWitness requirementWitness; + auto witnessTable = inheritanceDeclRef.getDecl()->witnessTable; + if(witnessTable && witnessTable->requirementDictionary.TryGetValue(requirementKey, requirementWitness)) + { + // The `inheritanceDeclRef` has substitutions applied to it that + // *aren't* present in the `requirementWitness`, because it was + // derived by the front-end when looking at the `InheritanceDecl` alone. + // + // We need to apply these substitutions here for the result to make sense. + // + // E.g., if we have a case like: + // + // interface ISidekick { associatedtype Hero; void follow(Hero hero); } + // struct Sidekick : ISidekick { typedef H Hero; void follow(H hero) {} }; + // + // void followHero(S s, S.Hero h) + // { + // s.follow(h); + // } + // + // Batman batman; + // Sidekick robin; + // followHero>(robin, batman); + // + // The second argument to `followHero` is `batman`, which has type `Batman`. + // The parameter declaration lists the type `S.Hero`, which is a reference + // to an associated type. The front end will expand this into something + // like `S.{S:ISidekick}.Hero` - that is, we'll end up with a declaration + // reference to `ISidekick.Hero` with a this-type substitution that references + // the `{S:ISidekick}` declaration as a witness. + // + // The front-end will expand the generic appliation `followHero>` + // to `followHero, {Sidekick:ISidekick}[H->Batman]>` + // (that is, the hidden second parameter will reference the inheritance + // clause on `Sidekick`, with a substitution to map `H` to `Batman`. + // + // This step should map the `{S:ISidekick}` declaration over to the + // concrete `{Sidekick:ISidekick}[H->Batman]` inheritance declaration. + // At that point `tryLookupRequirementWitness` might be called, because + // we want to look up the witness for the key `ISidekick.Hero` in the + // inheritance decl-ref that is `{Sidekick:ISidekick}[H->Batman]`. + // + // That lookup will yield us a reference to the typedef `Sidekick.Hero`, + // *without* any substitution for `H` (or rather, with a default one that + // maps `H` to `H`. + // + // So, in order to get the *right* end result, we need to apply + // the substitutions from the inheritance decl-ref to the witness. + // + requirementWitness = requirementWitness.specialize(inheritanceDeclRef.substitutions); + + return requirementWitness; + } + } } - return false; - } - RefPtr DeclRefType::CreateCanonicalType() - { - // A declaration reference is already canonical - return this; + // TODO: should handle the transitive case here too + + return RequirementWitness(); } RefPtr DeclRefType::SubstituteImpl(SubstitutionSet subst, int* ioDiff) @@ -579,9 +547,12 @@ void Type::accept(IValVisitor* visitor, void* extra) if (auto genericTypeParamDecl = dynamic_cast(declRef.getDecl())) { // search for a substitution that might apply to us - for (auto s = subst.genericSubstitutions; s; s = s->outer.Ptr()) + for(auto s = subst.substitutions; s; s = s->outer) { - auto genericSubst = s; + auto genericSubst = s.As(); + if(!genericSubst) + continue; + // the generic decl associated with the substitution list must be // the generic decl that declared this parameter auto genericDecl = genericSubst->genericDecl; @@ -611,50 +582,15 @@ void Type::accept(IValVisitor* visitor, void* extra) } } } - // the second case we care about is when this decl type refers to an associatedtype decl - // we want to replace it with the actual associated type - else if (auto assocTypeDecl = dynamic_cast(declRef.getDecl())) - { - auto thisSubst = getThisTypeSubst(declRef, false); - auto oldSubstSrc = thisSubst ? thisSubst->sourceType : nullptr; - bool restore = false; - if (thisSubst && thisSubst->sourceType.Ptr() == dynamic_cast(this)) - thisSubst->sourceType = nullptr; - auto newSubst = substituteSubstitutions(declRef.substitutions, subst, ioDiff); - if (restore) - thisSubst->sourceType = oldSubstSrc; - if (auto thisTypeSubst = newSubst.thisTypeSubstitution) - { - if (thisTypeSubst->sourceType) - { - if (auto aggTypeDeclRef = thisTypeSubst->sourceType.As()->declRef.As()) - { - Decl * targetType = nullptr; - if (aggTypeDeclRef.getDecl()->memberDictionary.TryGetValue(assocTypeDecl->getName(), targetType)) - { - if (auto typeDefDecl = dynamic_cast(targetType)) - { - DeclRef targetTypeDeclRef(typeDefDecl, aggTypeDeclRef.substitutions); - return GetType(targetTypeDeclRef); - } - else if (auto targetAggType = dynamic_cast(targetType)) - { - return DeclRefType::Create(getSession(), DeclRef(targetAggType, aggTypeDeclRef.substitutions)); - } - else - { - SLANG_UNIMPLEMENTED_X("unknown assoctype implementation type."); - } - } - } - } - } - } else if (auto globalGenParam = dynamic_cast(declRef.getDecl())) { // search for a substitution that might apply to us - for (auto genericSubst = subst.globalGenParamSubstitutions; genericSubst; genericSubst = genericSubst->outer.Ptr()) + for(auto s = subst.substitutions; s; s = s->outer) { + auto genericSubst = s.As(); + if(!genericSubst) + continue; + if (genericSubst->paramDecl == globalGenParam) { (*ioDiff)++; @@ -671,6 +607,45 @@ void Type::accept(IValVisitor* visitor, void* extra) // Make sure to record the difference! *ioDiff += diff; + // If this type is a reference to an associated type declaration, + // and the substitutions provide a "this type" substitution for + // the outer interface, then try to replace the type with the + // actual value of the associated type for the given implementation. + // + if(auto substAssocTypeDecl = substDeclRef.decl->As()) + { + for(auto s = substDeclRef.substitutions.substitutions; s; s = s->outer) + { + auto thisSubst = s.As(); + if(!thisSubst) + continue; + + if(auto interfaceDecl = substAssocTypeDecl->ParentDecl->As()) + { + if(thisSubst->interfaceDecl == interfaceDecl) + { + // We need to look up the declaration that satisfies + // the requirement named by the associated type. + Decl* requirementKey = substAssocTypeDecl; + RequirementWitness requirementWitness = tryLookUpRequirementWitness(thisSubst->witness, requirementKey); + switch(requirementWitness.getFlavor()) + { + default: + // No usable value was found, so there is nothing we can do. + break; + + case RequirementWitness::Flavor::val: + { + auto satisfyingVal = requirementWitness.getVal(); + return satisfyingVal; + } + break; + } + } + } + } + } + // Re-construct the type in case we are using a specialized sub-class return DeclRefType::Create(getSession(), substDeclRef); } @@ -689,9 +664,7 @@ void Type::accept(IValVisitor* visitor, void* extra) return intVal; } - // TODO: need to figure out how to unify this with the logic - // in the generic case... - DeclRefType* DeclRefType::Create( + DeclRef createDefaultSubstitutionsIfNeeded( Session* session, DeclRef declRef) { @@ -701,30 +674,81 @@ void Type::accept(IValVisitor* visitor, void* extra) // within its own member functions). To handle this case, // we will construct a default specialization at the use // site if needed. + // + // This same logic should also apply to declarations nested + // more than one level inside of a generic (e.g., a `typdef` + // inside of a generic `struct`). + // + // Similarly, it needs to work for multiple levels of + // nested generics. + // + + // We are going to build up a list of substitutions that need + // to be applied to the decl-ref to make it specialized. + RefPtr substsToApply; + RefPtr* link = &substsToApply; - if (auto genericParent = declRef.GetParent().As()) + RefPtr dd = declRef.getDecl(); + for(;;) { - auto subst = declRef.substitutions; - // try find a substitution targeting this generic decl - bool substFound = false; - for (auto genSubst = subst.genericSubstitutions; genSubst; genSubst = genSubst->outer) + RefPtr childDecl = dd; + RefPtr parentDecl = dd->ParentDecl; + if(!parentDecl) + break; + + dd = parentDecl; + + if(auto genericParentDecl = parentDecl.As()) { - if (genSubst->genericDecl == genericParent.decl) + // Don't specialize any parameters of a generic. + if(childDecl != genericParentDecl->inner) + break; + + // We have a generic ancestor, but do we have an substitutions for it? + RefPtr foundSubst; + for(auto s = declRef.substitutions.substitutions; s; s = s->outer) { - substFound = true; + auto genSubst = s.As(); + if(!genSubst) + continue; + + if(genSubst->genericDecl != genericParentDecl) + continue; + + // Okay, we found a matching substitution, + // so there is nothing to be done. + foundSubst = genSubst; break; } - } - // we did not find an existing substituion, create a default one - if (!substFound) - { - declRef.substitutions = createDefaultSubstitutions( - session, - declRef.decl, - subst); + + if(!foundSubst) + { + RefPtr newSubst = createDefaultSubsitutionsForGeneric( + session, + genericParentDecl, + nullptr); + + *link = newSubst; + link = &newSubst->outer; + } } } + if(!substsToApply) + return declRef; + + int diff = 0; + return declRef.SubstituteImpl(substsToApply, &diff); + } + + // TODO: need to figure out how to unify this with the logic + // in the generic case... + DeclRefType* DeclRefType::Create( + Session* session, + DeclRef declRef) + { + declRef = createDefaultSubstitutionsIfNeeded(session, declRef); + if (auto builtinMod = declRef.getDecl()->FindModifier()) { auto type = new BasicExpressionType(builtinMod->tag); @@ -734,7 +758,15 @@ void Type::accept(IValVisitor* visitor, void* extra) } else if (auto magicMod = declRef.getDecl()->FindModifier()) { - GenericSubstitution* subst = declRef.substitutions.genericSubstitutions.Ptr(); + GenericSubstitution* subst = nullptr; + for(auto s = declRef.substitutions.substitutions; s; s = s->outer) + { + if(auto genericSubst = s.As()) + { + subst = genericSubst; + break; + } + } if (magicMod->name == "SamplerState") { @@ -910,28 +942,6 @@ void Type::accept(IValVisitor* visitor, void* extra) return (int)(int64_t)(void*)this; } - // IRBasicBlockType - - String IRBasicBlockType::ToString() - { - return "Block"; - } - - bool IRBasicBlockType::EqualsImpl(Type * /*type*/) - { - return false; - } - - RefPtr IRBasicBlockType::CreateCanonicalType() - { - return this; - } - - int IRBasicBlockType::GetHashCode() - { - return (int)(int64_t)(void*)this; - } - // InitializerListType String InitializerListType::ToString() @@ -1196,6 +1206,18 @@ void Type::accept(IValVisitor* visitor, void* extra) return elementType->AsBasicType(); } + // + + RefPtr findInnerMostGenericSubstitution(Substitutions* subst) + { + for(RefPtr s = subst; s; s = s->outer) + { + if(auto genericSubst = s.As()) + return genericSubst; + } + return nullptr; + } + // MatrixExpressionType String MatrixExpressionType::ToString() @@ -1212,24 +1234,24 @@ void Type::accept(IValVisitor* visitor, void* extra) Type* MatrixExpressionType::getElementType() { - return this->declRef.substitutions.genericSubstitutions->args[0].As().Ptr(); + return findInnerMostGenericSubstitution(declRef.substitutions)->args[0].As().Ptr(); } IntVal* MatrixExpressionType::getRowCount() { - return this->declRef.substitutions.genericSubstitutions->args[1].As().Ptr(); + return findInnerMostGenericSubstitution(declRef.substitutions)->args[1].As().Ptr(); } IntVal* MatrixExpressionType::getColumnCount() { - return this->declRef.substitutions.genericSubstitutions->args[2].As().Ptr(); + return findInnerMostGenericSubstitution(declRef.substitutions)->args[2].As().Ptr(); } // PtrTypeBase Type* PtrTypeBase::getValueType() { - return this->declRef.substitutions.genericSubstitutions->args[0].As().Ptr(); + return findInnerMostGenericSubstitution(declRef.substitutions)->args[0].As().Ptr(); } // GenericParamIntVal @@ -1256,9 +1278,13 @@ void Type::accept(IValVisitor* visitor, void* extra) RefPtr GenericParamIntVal::SubstituteImpl(SubstitutionSet subst, int* ioDiff) { // search for a substitution that might apply to us - for (auto genSubst = subst.genericSubstitutions; genSubst; genSubst = genSubst->outer.Ptr()) + for(auto s = subst.substitutions; s; s = s->outer) { - // the generic decl associated with the substitution list must be + auto genSubst = s.As(); + if(!genSubst) + continue; + + // the generic decl associated with the substitution list must be // the generic decl that declared this parameter auto genericDecl = genSubst->genericDecl; if (genericDecl != declRef.getDecl()->ParentDecl) @@ -1293,17 +1319,18 @@ void Type::accept(IValVisitor* visitor, void* extra) // Substitutions - RefPtr GenericSubstitution::SubstituteImpl(SubstitutionSet subst, int* ioDiff) + RefPtr GenericSubstitution::applySubstitutionsShallow(SubstitutionSet substSet, RefPtr substOuter, int* ioDiff) { if (!this) return nullptr; int diff = 0; - auto outerSubst = outer ? outer->SubstituteImpl(subst, &diff) : nullptr; + + if(substOuter != outer) diff++; List> substArgs; for (auto a : args) { - substArgs.Add(a->SubstituteImpl(subst, &diff)); + substArgs.Add(a->SubstituteImpl(substSet, &diff)); } if (!diff) return this; @@ -1312,7 +1339,7 @@ void Type::accept(IValVisitor* visitor, void* extra) auto substSubst = new GenericSubstitution(); substSubst->genericDecl = genericDecl; substSubst->args = substArgs; - substSubst->outer = outerSubst.As(); + substSubst->outer = substOuter; return substSubst; } @@ -1344,75 +1371,72 @@ void Type::accept(IValVisitor* visitor, void* extra) return true; } - RefPtr ThisTypeSubstitution::SubstituteImpl(SubstitutionSet subst, int* ioDiff) + RefPtr ThisTypeSubstitution::applySubstitutionsShallow(SubstitutionSet substSet, RefPtr substOuter, int* ioDiff) { if (!this) return nullptr; int diff = 0; - RefPtr newSourceType; - if (sourceType) - newSourceType = sourceType->SubstituteImpl(subst, &diff); - else - { - // this_type is a free variable, use this_type from subst - if (subst.thisTypeSubstitution) - { - if (subst.thisTypeSubstitution->sourceType != sourceType) - { - newSourceType = subst.thisTypeSubstitution->sourceType; - diff = 1; - } - } - } + + if(substOuter != outer) diff++; + auto substWitness = witness->SubstituteImpl(substSet, &diff).As(); + if (!diff) return this; (*ioDiff)++; auto substSubst = new ThisTypeSubstitution(); - substSubst->sourceType = newSourceType; + substSubst->interfaceDecl = interfaceDecl; + substSubst->witness = substWitness; + substSubst->outer = substOuter; return substSubst; } bool ThisTypeSubstitution::Equals(Substitutions* subst) { if (!subst) - return true; + return this == nullptr; if (auto thisTypeSubst = dynamic_cast(subst)) { - if (!sourceType || !thisTypeSubst->sourceType) - return true; - return sourceType->EqualsVal(thisTypeSubst->sourceType); + return witness->EqualsVal(thisTypeSubst->witness); } return false; } - RefPtr GlobalGenericParamSubstitution::SubstituteImpl(SubstitutionSet subst, int* ioDiff) + int ThisTypeSubstitution::GetHashCode() const + { + return witness->GetHashCode(); + } + + RefPtr GlobalGenericParamSubstitution::applySubstitutionsShallow(SubstitutionSet substSet, RefPtr substOuter, int* ioDiff) { // if we find a GlobalGenericParamSubstitution in subst that references the same __generic_param decl // return a copy of that GlobalGenericParamSubstitution int diff = 0; - RefPtr outerSubst = outer ? outer->SubstituteImpl(subst, &diff) : nullptr; - for (auto gSubst = subst.globalGenParamSubstitutions; gSubst; gSubst = gSubst->outer) - { - if (gSubst->paramDecl == paramDecl) - { - // substitute only if we are really different - if (!gSubst->actualType->EqualsVal(actualType)) - { - RefPtr rs = new GlobalGenericParamSubstitution(*gSubst); - rs->outer = outerSubst.As(); - return rs; - } - } - } - if (diff) + if(substOuter != outer) diff++; + + auto substActualType = actualType->SubstituteImpl(substSet, &diff).As(); + + List substConstraintArgs; + for(auto constraintArg : constraintArgs) { - *ioDiff++; - RefPtr rs = new GlobalGenericParamSubstitution(*this); - rs->outer = outerSubst.As(); - return rs; + ConstraintArg substConstraintArg; + substConstraintArg.decl = constraintArg.decl; + substConstraintArg.val = constraintArg.val->SubstituteImpl(substSet, &diff); + + substConstraintArgs.Add(substConstraintArg); } - return this; + + if(!diff) + return this; + + (*ioDiff)++; + + RefPtr substSubst = new GlobalGenericParamSubstitution(); + substSubst->paramDecl = paramDecl; + substSubst->actualType = substActualType; + substSubst->constraintArgs = substConstraintArgs; + substSubst->outer = substOuter; + return substSubst; } bool GlobalGenericParamSubstitution::Equals(Substitutions* subst) @@ -1425,13 +1449,11 @@ void Type::accept(IValVisitor* visitor, void* extra) return false; if (!actualType->EqualsVal(genSubst->actualType)) return false; - if (witnessTables.Count() != genSubst->witnessTables.Count()) + if (constraintArgs.Count() != genSubst->constraintArgs.Count()) return false; - for (UInt i = 0; i < witnessTables.Count(); i++) + for (UInt i = 0; i < constraintArgs.Count(); i++) { - if (!witnessTables[i].Key->Equals(genSubst->witnessTables[i].Key)) - return false; - if (!witnessTables[i].Value->EqualsVal(genSubst->witnessTables[i].Value)) + if (!constraintArgs[i].val->EqualsVal(genSubst->constraintArgs[i].val)) return false; } return true; @@ -1474,74 +1496,354 @@ void Type::accept(IValVisitor* visitor, void* extra) UNREACHABLE_RETURN(expr); } - bool hasGlobalGenericSubst(SubstitutionSet destSubst, GlobalGenericParamSubstitution * genSubst) + void buildMemberDictionary(ContainerDecl* decl); + + InterfaceDecl* findOuterInterfaceDecl(Decl* decl) { - for (auto subst = destSubst.globalGenParamSubstitutions; subst; subst = subst->outer) + Decl* dd = decl; + while(dd) { - if (subst->paramDecl == genSubst->paramDecl) - return true; + if(auto interfaceDecl = dd->As()) + return interfaceDecl; + + dd = dd->ParentDecl; } - return false; + return nullptr; } - void insertGlobalGenericSubstitutions(SubstitutionSet & destSubst, SubstitutionSet srcSubst, int * ioDiff) + + RefPtr findGlobalGenericSubst( + RefPtr substs, + GlobalGenericParamDecl* paramDecl) { - int diff = 0; - - if (auto globalGenSubst = srcSubst.globalGenParamSubstitutions) + for(auto s = substs; s; s = s->outer) { - if (!hasGlobalGenericSubst(destSubst, globalGenSubst)) - { - RefPtr cpyGlobalGenSubst = new GlobalGenericParamSubstitution(*globalGenSubst); - cpyGlobalGenSubst->outer = destSubst.globalGenParamSubstitutions; - destSubst.globalGenParamSubstitutions = cpyGlobalGenSubst; - diff = 1; - } + auto gSubst = s.As(); + if(!gSubst) + continue; + + if(gSubst->paramDecl != paramDecl) + continue; + + return gSubst; } - *ioDiff += diff; + + return nullptr; } - void buildMemberDictionary(ContainerDecl* decl); + RefPtr specializeSubstitutionsShallow( + RefPtr substToSpecialize, + RefPtr substsToApply, + RefPtr restSubst, + int* ioDiff) + { + return substToSpecialize->applySubstitutionsShallow(substsToApply, restSubst, ioDiff); + } - DeclRefBase DeclRefBase::SubstituteImpl(SubstitutionSet subst, int* ioDiff) + RefPtr specializeGlobalGenericSubstitutions( + Decl* declToSpecialize, + RefPtr substsToSpecialize, + RefPtr substsToApply, + int* ioDiff, + HashSet& ioParametersFound) { - int diff = 0; - auto substSubst = substituteSubstitutions(substitutions, subst, &diff); - if (!diff) - return *this; + // Any existing global-generic substitutions will trigger + // a recursive case that skips the rest of the function. + for(auto specSubst = substsToSpecialize; specSubst; specSubst = specSubst->outer) + { + auto specGlobalGenericSubst = specSubst.As(); + if(!specGlobalGenericSubst) + continue; - *ioDiff += diff; + ioParametersFound.Add(specGlobalGenericSubst->paramDecl); - DeclRefBase substDeclRef; - substDeclRef.decl = decl; - substDeclRef.substitutions = substSubst; - - // if this is a AssocTypeDecl, try lookup the actual associated type - if (auto assocTypeDecl = substDeclRef.decl->As()) + int diff = 0; + auto restSubst = specializeGlobalGenericSubstitutions( + declToSpecialize, + specSubst->outer, + substsToApply, + &diff, + ioParametersFound); + + auto firstSubst = specializeSubstitutionsShallow( + specGlobalGenericSubst, + substsToApply, + restSubst, + &diff); + + *ioDiff += diff; + return firstSubst; + } + + // No more existing substitutions, so we know we can apply + // our global generic substitutions without any special work. + + // We expect global generic substitutions to come at + // the end of the list in all cases, so lets advance + // until we see them. + RefPtr appGlobalGenericSubsts = substsToApply; + while(appGlobalGenericSubsts && !appGlobalGenericSubsts.As()) + appGlobalGenericSubsts = appGlobalGenericSubsts->outer; + + + // If there is nothing to apply, then we are done + if(!appGlobalGenericSubsts) + return nullptr; + + // Otherwise, it seems like something has to change. + (*ioDiff)++; + + // If there were no parameters bound by the existing substitution, + // then we can safely use the global generics from the to-apply set. + if(ioParametersFound.Count() == 0) + return appGlobalGenericSubsts; + + RefPtr resultSubst; + RefPtr* link = &resultSubst; + for(auto appSubst = appGlobalGenericSubsts; appSubst; appSubst = appSubst->outer) { - auto thisSubst = getThisTypeSubst(substDeclRef, false); - if (thisSubst) + auto appGlobalGenericSubst = appSubst.As(); + if(!appSubst) + continue; + + // Don't include substitutions for parameters already handled. + if(ioParametersFound.Contains(appGlobalGenericSubst->paramDecl)) + continue; + + RefPtr newSubst = new GlobalGenericParamSubstitution(); + newSubst->paramDecl = appGlobalGenericSubst->paramDecl; + newSubst->actualType = appGlobalGenericSubst->actualType; + newSubst->constraintArgs = appGlobalGenericSubst->constraintArgs; + + *link = newSubst; + link = &newSubst->outer; + } + + return resultSubst; + } + + RefPtr specializeGlobalGenericSubstitutions( + Decl* declToSpecialize, + RefPtr substsToSpecialize, + RefPtr substsToApply, + int* ioDiff) + { + // Keep track of any parameters already present in the + // existing substitution. + HashSet parametersFound; + return specializeGlobalGenericSubstitutions(declToSpecialize, substsToSpecialize, substsToApply, ioDiff, parametersFound); + } + + + // Construct new substitutions to apply to a declaration, + // based on a provided substituion set to be applied + RefPtr specializeSubstitutions( + Decl* declToSpecialize, + RefPtr substsToSpecialize, + RefPtr substsToApply, + int* ioDiff) + { + // No declaration? Then nothing to specialize. + if(!declToSpecialize) + return nullptr; + + // No (remaining) substitutions to apply? Then we are done. + if(!substsToApply) + return substsToSpecialize; + + // Walk the hierarchy of the declaration to determine what specializations might apply. + // We assume that the `substsToSpecialize` must be aligned with the ancestor + // hierarchy of `declToSpecialize` such that if, e.g., the `declToSpecialize` is + // nested directly in a generic, then `substToSpecialize` will either start with + // the corresponding `GenericSubstitution` or there will be *no* generic substitutions + // corresponding to that decl. + for(Decl* ancestorDecl = declToSpecialize; ancestorDecl; ancestorDecl = ancestorDecl->ParentDecl) + { + if(auto ancestorGenericDecl = ancestorDecl->As()) { - if (auto declRefType = thisSubst->sourceType.As()) + // The declaration is nested inside a generic. + // Does it already have a specialization for that generic? + if(auto specGenericSubst = substsToSpecialize.As()) { - if (auto aggDeclRef = declRefType->declRef.As()) + if(specGenericSubst->genericDecl == ancestorGenericDecl) { - Decl* subTypeDecl = nullptr; - buildMemberDictionary(aggDeclRef.getDecl()); - SLANG_ASSERT(aggDeclRef.getDecl()->memberDictionaryIsValid); - aggDeclRef.getDecl()->memberDictionary.TryGetValue(assocTypeDecl->getName(), subTypeDecl); - if (auto typeDefDecl = subTypeDecl->As()) - { - auto t = GetType(DeclRef(typeDefDecl, aggDeclRef.substitutions)); - auto canonicalType = t->GetCanonicalType()->AsDeclRefType(); - SLANG_ASSERT(canonicalType); - return canonicalType->declRef; - } - SLANG_ASSERT(subTypeDecl); - return DeclRefBase(subTypeDecl, aggDeclRef.substitutions); + // Yes. We have an existing specialization, so we will + // keep one matching it in place. + int diff = 0; + auto restSubst = specializeSubstitutions( + ancestorGenericDecl->ParentDecl, + specGenericSubst->outer, + substsToApply, + &diff); + + auto firstSubst = specializeSubstitutionsShallow( + specGenericSubst, + substsToApply, + restSubst, + &diff); + + *ioDiff += diff; + return firstSubst; + } + } + + // If the declaration is not already specialized + // for the given generic, then see if we are trying + // to *apply* such specializations to it. + // + // TODO: The way we handle things right now with + // "default" specializations, this case shouldn't + // actually come up. + // + for(auto s = substsToApply; s; s = s->outer) + { + auto appGenericSubst = s.As(); + if(!appGenericSubst) + continue; + + if(appGenericSubst->genericDecl != ancestorGenericDecl) + continue; + + // The substitutions we are applying are trying + // to specialize this generic, but we don't already + // have a generic substitution in place. + // We will need to create one. + + int diff = 0; + auto restSubst = specializeSubstitutions( + ancestorGenericDecl->ParentDecl, + substsToSpecialize, + substsToApply, + &diff); + + RefPtr firstSubst = new GenericSubstitution(); + firstSubst->genericDecl = ancestorGenericDecl; + firstSubst->args = appGenericSubst->args; + firstSubst->outer = restSubst; + + (*ioDiff)++; + return firstSubst; + } + } + else if(auto ancestorInterfaceDecl = ancestorDecl->As()) + { + // The task is basically the same as for the generic case: + // We want to see if there is any existing substitution that + // applies to this declaration, and use that if possible. + + // The declaration is nested inside a generic. + // Does it already have a specialization for that generic? + if(auto specThisTypeSubst = substsToSpecialize.As()) + { + if(specThisTypeSubst->interfaceDecl == ancestorInterfaceDecl) + { + // Yes. We have an existing specialization, so we will + // keep one matching it in place. + int diff = 0; + auto restSubst = specializeSubstitutions( + ancestorInterfaceDecl->ParentDecl, + specThisTypeSubst->outer, + substsToApply, + &diff); + + auto firstSubst = specializeSubstitutionsShallow( + specThisTypeSubst, + substsToApply, + restSubst, + &diff); + + *ioDiff += diff; + return firstSubst; } } + + // Otherwise, check if we are trying to apply + // a this-type substitution to the given interface + // + for(auto s = substsToApply; s; s = s->outer) + { + auto appThisTypeSubst = s.As(); + if(!appThisTypeSubst) + continue; + + if(appThisTypeSubst->interfaceDecl != ancestorInterfaceDecl) + continue; + + int diff = 0; + auto restSubst = specializeSubstitutions( + ancestorInterfaceDecl->ParentDecl, + substsToSpecialize, + substsToApply, + &diff); + + RefPtr firstSubst = new ThisTypeSubstitution(); + firstSubst->interfaceDecl = ancestorInterfaceDecl; + firstSubst->witness = appThisTypeSubst->witness; + firstSubst->outer = restSubst; + + (*ioDiff)++; + return firstSubst; + } } } + + // If we reach here then we've walked the full hierarchy up from + // `declToSpecialize` and either didn't run into an generic/interface + // declarations, or we didn't find any attempt to specialize them + // in either substitution. + // + // As an invariant, there should *not* be any generic or this-type + // substitutiosn in `substToSpecialize`, because otherwise they + // would be specializations that don't actually apply to the given + // declaration. + // + // The remaining substitutions to apply, if any, should thus be + // global-generic substitutions. And similarly, those are the + // only remaining substitutions we really care about in + // `substsToApply`. + // + // Note: this does *not* mean that `substsToApply` doesn't have + // any generic or this-type substitutions; it just means that none + // of them were applicable. + // + return specializeGlobalGenericSubstitutions( + declToSpecialize, + substsToSpecialize, + substsToApply, + ioDiff); + } + + DeclRefBase DeclRefBase::SubstituteImpl(SubstitutionSet substSet, int* ioDiff) + { + // Nothing to do when we have no declaration. + if(!decl) + return *this; + + // Apply the given substitutions to any specializations + // that have already been applied to this declaration. + int diff = 0; + + auto substSubst = specializeSubstitutions( + decl, + substitutions.substitutions, + substSet.substitutions, + &diff); + + if (!diff) + return *this; + + *ioDiff += diff; + + DeclRefBase substDeclRef; + substDeclRef.decl = decl; + substDeclRef.substitutions = substSubst; + + // TODO: The old code here used to try to translate a decl-ref + // to an associated type in a decl-ref for the concrete type + // in a paarticular implementation. + // + // I have only kept that logic in `DeclRefType::SubstituteImpl`, + // but it may turn out it is needed here too. + return substDeclRef; } @@ -1569,32 +1871,45 @@ void Type::accept(IValVisitor* visitor, void* extra) if (!parentDecl) return DeclRefBase(); - if (auto parentGeneric = dynamic_cast(parentDecl)) + // Default is to apply the same set of substitutions/specializations + // to the parent declaration as were applied to the child. + RefPtr substToApply = substitutions.substitutions; + + if(auto interfaceDecl = dynamic_cast(decl)) { - auto genSubst = substitutions.genericSubstitutions; - if (genSubst && genSubst->genericDecl == parentDecl) - { - // We strip away the specializations that were applied to - // the parent, since we were asked for a reference *to* the parent. - return DeclRefBase(parentGeneric, SubstitutionSet(genSubst->outer, substitutions.thisTypeSubstitution, - substitutions.globalGenParamSubstitutions)); - } - else + // The declaration being referenced is an `interface` declaration, + // and there might be a this-type substitution in place. + // A reference to the parent of the interface declaration + // should not include that substitution. + if(auto thisTypeSubst = substToApply.As()) { - // Either we don't have specializations, or the inner-most - // specializations didn't apply to the parent decl. This - // can happen if we are looking at an unspecialized - // declaration that is a child of a generic. - return DeclRefBase(parentGeneric, substitutions); + if(thisTypeSubst->interfaceDecl == interfaceDecl) + { + // Strip away that specializations that apply to the interface. + substToApply = thisTypeSubst->outer; + } } } - else + + if (auto parentGenericDecl = dynamic_cast(parentDecl)) { - // If the parent isn't a generic, then it must - // use the same specializations as this declaration - return DeclRefBase(parentDecl, substitutions); + // The parent of this declaration is a generic, which means + // that the decl-ref to the current declaration might include + // substitutiosn that specialize the generic parameters. + // A decl-ref to the parent generic should *not* include + // those substitutions. + // + if(auto genericSubst = substToApply.As()) + { + if(genericSubst->genericDecl == parentGenericDecl) + { + // Strip away the specializations that were applied to the parent. + substToApply = genericSubst->outer; + } + } } + return DeclRefBase(parentDecl, substToApply); } int DeclRefBase::GetHashCode() const @@ -1706,12 +2021,12 @@ void Type::accept(IValVisitor* visitor, void* extra) Type* HLSLPatchType::getElementType() { - return this->declRef.substitutions.genericSubstitutions->args[0].As().Ptr(); + return findInnerMostGenericSubstitution(declRef.substitutions)->args[0].As().Ptr(); } IntVal* HLSLPatchType::getElementCount() { - return this->declRef.substitutions.genericSubstitutions->args[1].As().Ptr(); + return findInnerMostGenericSubstitution(declRef.substitutions)->args[1].As().Ptr(); } // Constructors for types @@ -1742,7 +2057,9 @@ void Type::accept(IValVisitor* visitor, void* extra) Session* session, DeclRef const& declRef) { - auto namedType = new NamedExpressionType(declRef); + DeclRef specializedDeclRef = createDefaultSubstitutionsIfNeeded(session, declRef).As(); + + auto namedType = new NamedExpressionType(specializedDeclRef); namedType->setSession(session); return namedType; } @@ -1828,64 +2145,141 @@ void Type::accept(IValVisitor* visitor, void* extra) && declRef.Equals(otherWitness->declRef); } + RefPtr findThisTypeSubstitution( + Substitutions* substs, + InterfaceDecl* interfaceDecl) + { + for(RefPtr s = substs; s; s = s->outer) + { + auto thisTypeSubst = s.As(); + if(!thisTypeSubst) + continue; + + if(thisTypeSubst->interfaceDecl != interfaceDecl) + continue; + + return thisTypeSubst; + } + + return nullptr; + } + RefPtr DeclaredSubtypeWitness::SubstituteImpl(SubstitutionSet subst, int * ioDiff) { - if (auto genConstraintDecl = declRef.As()) + if (auto genConstraintDeclRef = declRef.As()) { + auto genConstraintDecl = genConstraintDeclRef.getDecl(); + // search for a substitution that might apply to us - for (auto genericSubst = subst.genericSubstitutions; genericSubst; genericSubst = genericSubst->outer.Ptr()) + for(auto s = subst.substitutions; s; s = s->outer) { - // the generic decl associated with the substitution list must be - // the generic decl that declared this parameter - auto genericDecl = genericSubst->genericDecl; - if (genericDecl != genConstraintDecl.getDecl()->ParentDecl) - continue; - bool found = false; - UInt index = 0; - for (auto m : genericDecl->Members) + if(auto genericSubst = s.As()) { - if (auto constraintParam = m.As()) + // the generic decl associated with the substitution list must be + // the generic decl that declared this parameter + auto genericDecl = genericSubst->genericDecl; + if (genericDecl != genConstraintDecl->ParentDecl) + continue; + + bool found = false; + UInt index = 0; + for (auto m : genericDecl->Members) { - if (constraintParam.Ptr() == declRef.getDecl()) + if (auto constraintParam = m.As()) { - found = true; - break; + if (constraintParam.Ptr() == declRef.getDecl()) + { + found = true; + break; + } + index++; } - index++; + } + if (found) + { + (*ioDiff)++; + auto ordinaryParamCount = genericDecl->getMembersOfType().Count() + + genericDecl->getMembersOfType().Count(); + SLANG_ASSERT(index + ordinaryParamCount < genericSubst->args.Count()); + return genericSubst->args[index + ordinaryParamCount]; } } - if (found) + else if(auto globalGenericSubst = s.As()) { - (*ioDiff)++; - auto ordinaryParamCount = genericDecl->getMembersOfType().Count() + - genericDecl->getMembersOfType().Count(); - SLANG_ASSERT(index + ordinaryParamCount < genericSubst->args.Count()); - return genericSubst->args[index + ordinaryParamCount]; + // check if the substitution is really about this global generic type parameter + if (globalGenericSubst->paramDecl != genConstraintDecl->ParentDecl) + continue; + + for(auto constraintArg : globalGenericSubst->constraintArgs) + { + if(constraintArg.decl.Ptr() != genConstraintDecl) + continue; + + (*ioDiff)++; + return constraintArg.val; + } } } - for (auto globalGenParamSubst = subst.globalGenParamSubstitutions; globalGenParamSubst; globalGenParamSubst = globalGenParamSubst->outer.Ptr()) - { - // we have a GlobalGenericParamSubstitution, this substitution will provide - // a concrete IRWitnessTable for a generic global variable - auto supType = GetSup(genConstraintDecl); + } - // check if the substitution is really about this global generic type parameter - if (globalGenParamSubst->paramDecl != genConstraintDecl.getDecl()->ParentDecl) - continue; + // Perform substitution on the constituent elements. + int diff = 0; + auto substSub = sub->SubstituteImpl(subst, &diff).As(); + auto substSup = sup->SubstituteImpl(subst, &diff).As(); + auto substDeclRef = declRef.SubstituteImpl(subst, &diff); + if (!diff) + return this; + + (*ioDiff)++; - // find witness table for the required interface - for (auto witness : globalGenParamSubst->witnessTables) - if (witness.Key->EqualsVal(supType)) + // If we have a reference to a type constraint for an + // associated type declaration, then we can replace it + // with the concrete conformance witness for a concrete + // type implementing the outer interface. + // + // TODO: It is a bit gross that we use `GenericTypeConstraintDecl` for + // associated types, when they aren't really generic type *parameters*, + // so we'll need to change this location in the code if we ever clean + // up the hierarchy. + // + if (auto substTypeConstraintDecl = substDeclRef.decl->As()) + { + if (auto substAssocTypeDecl = substTypeConstraintDecl->ParentDecl->As()) + { + if (auto interfaceDecl = substAssocTypeDecl->ParentDecl->As()) + { + // At this point we have a constraint decl for an associated type, + // and we nee to see if we are dealing with a concrete substitution + // for the interface around that associated type. + if(auto thisTypeSubst = findThisTypeSubstitution(substDeclRef.substitutions, interfaceDecl)) { - (*ioDiff)++; - return witness.Value; + // We need to look up the declaration that satisfies + // the requirement named by the associated type. + Decl* requirementKey = substTypeConstraintDecl; + RequirementWitness requirementWitness = tryLookUpRequirementWitness(thisTypeSubst->witness, requirementKey); + switch(requirementWitness.getFlavor()) + { + default: + break; + + case RequirementWitness::Flavor::val: + { + auto satisfyingVal = requirementWitness.getVal(); + return satisfyingVal; + } + } } + } } } + + + + RefPtr rs = new DeclaredSubtypeWitness(); - rs->sub = sub->SubstituteImpl(subst, ioDiff).As(); - rs->sup = sup->SubstituteImpl(subst, ioDiff).As(); - rs->declRef = declRef.SubstituteImpl(subst, ioDiff); + rs->sub = substSub; + rs->sup = substSup; + rs->declRef = substDeclRef; return rs; } @@ -1918,7 +2312,7 @@ void Type::accept(IValVisitor* visitor, void* extra) return sub->Equals(otherWitness->sub) && sup->Equals(otherWitness->sup) && subToMid->EqualsVal(otherWitness->subToMid) - && midToSup->EqualsVal(otherWitness->midToSup); + && midToSup.Equals(otherWitness->midToSup); } RefPtr TransitiveSubtypeWitness::SubstituteImpl(SubstitutionSet subst, int * ioDiff) @@ -1928,7 +2322,7 @@ void Type::accept(IValVisitor* visitor, void* extra) RefPtr substSub = sub->SubstituteImpl(subst, &diff).As(); RefPtr substSup = sup->SubstituteImpl(subst, &diff).As(); RefPtr substSubToMid = subToMid->SubstituteImpl(subst, &diff).As(); - RefPtr substMidToSup = midToSup->SubstituteImpl(subst, &diff).As(); + DeclRef substMidToSup = midToSup.SubstituteImpl(subst, &diff); // If nothing changed, then we can bail out early. if (!diff) @@ -1971,7 +2365,7 @@ void Type::accept(IValVisitor* visitor, void* extra) sb << "TransitiveSubtypeWitness("; sb << this->subToMid->ToString(); sb << ", "; - sb << this->midToSup->ToString(); + sb << this->midToSup.toString(); sb << ")"; return sb.ProduceString(); } @@ -1981,29 +2375,7 @@ void Type::accept(IValVisitor* visitor, void* extra) auto hash = sub->GetHashCode(); hash = combineHash(hash, sup->GetHashCode()); hash = combineHash(hash, subToMid->GetHashCode()); - hash = combineHash(hash, midToSup->GetHashCode()); - return hash; - } - - // IRProxyVal - - bool IRProxyVal::EqualsVal(Val* val) - { - auto otherProxy = dynamic_cast(val); - if(!otherProxy) - return false; - - return this->inst.get() == otherProxy->inst.get(); - } - - String IRProxyVal::ToString() - { - return "IRProxyVal(...)"; - } - - int IRProxyVal::GetHashCode() - { - auto hash = Slang::GetHashCode(inst.get()); + hash = combineHash(hash, midToSup.GetHashCode()); return hash; } @@ -2020,77 +2392,19 @@ void Type::accept(IValVisitor* visitor, void* extra) return name->text; } - RefPtr getThisTypeSubst(DeclRefBase & declRef, bool insertSubstEntry) - { - RefPtr thisSubst = declRef.substitutions.thisTypeSubstitution; - if (!thisSubst) - { - thisSubst = new ThisTypeSubstitution(); - if (insertSubstEntry) - { - declRef.substitutions.thisTypeSubstitution = thisSubst; - } - } - return thisSubst; - } - - RefPtr getNewThisTypeSubst(DeclRefBase & declRef) - { - declRef.substitutions.thisTypeSubstitution = new ThisTypeSubstitution(); - return declRef.substitutions.thisTypeSubstitution; - } - - SubstitutionSet substituteSubstitutions(SubstitutionSet oldSubst, SubstitutionSet subst, int * ioDiff) - { - return oldSubst.substituteImpl(subst, ioDiff); - } - bool SubstitutionSet::Equals(SubstitutionSet substSet) const { - if (genericSubstitutions) - { - if (!genericSubstitutions->Equals(substSet.genericSubstitutions)) - return false; - } - else - { - if (substSet.genericSubstitutions) - return false; - } - if (thisTypeSubstitution) - { - if (!thisTypeSubstitution->Equals(substSet.thisTypeSubstitution)) - return false; - } - else - { - if (substSet.thisTypeSubstitution && substSet.thisTypeSubstitution->sourceType != nullptr) - return false; - } - return true; - } - SubstitutionSet SubstitutionSet::substituteImpl(SubstitutionSet subst, int * ioDiff) - { - SubstitutionSet rs; - if (genericSubstitutions) - rs.genericSubstitutions = genericSubstitutions->SubstituteImpl(subst, ioDiff).As(); - if (globalGenParamSubstitutions) - rs.globalGenParamSubstitutions = globalGenParamSubstitutions->SubstituteImpl(subst, ioDiff).As(); - if (thisTypeSubstitution) - rs.thisTypeSubstitution = thisTypeSubstitution->SubstituteImpl(subst, ioDiff).As(); + if(!substitutions || !substSet.substitutions) + return substitutions == substSet.substitutions; - insertGlobalGenericSubstitutions(rs, subst, ioDiff); - return rs; + return substitutions->Equals(substSet.substitutions); } + int SubstitutionSet::GetHashCode() const { int rs = 0; - if (genericSubstitutions) - rs = combineHash(rs, genericSubstitutions->GetHashCode()); - if (thisTypeSubstitution) - rs = combineHash(rs, thisTypeSubstitution->GetHashCode()); - if (globalGenParamSubstitutions) - rs = combineHash(rs, globalGenParamSubstitutions->GetHashCode()); + if (substitutions) + rs = combineHash(rs, substitutions->GetHashCode()); return rs; } } -- cgit v1.2.3