diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/slang-ast-serialize.cpp | 2 | ||||
| -rw-r--r-- | source/slang/slang-ast-support-types.h | 6 | ||||
| -rw-r--r-- | source/slang/slang-ast-val.cpp | 8 | ||||
| -rw-r--r-- | source/slang/slang-ast-val.h | 7 | ||||
| -rw-r--r-- | source/slang/slang-check-conformance.cpp | 9 | ||||
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 46 | ||||
| -rw-r--r-- | source/slang/slang-check-overload.cpp | 1 | ||||
| -rw-r--r-- | source/slang/slang-lookup.cpp | 115 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 69 |
9 files changed, 177 insertions, 86 deletions
diff --git a/source/slang/slang-ast-serialize.cpp b/source/slang/slang-ast-serialize.cpp index 141bed368..6eaa29968 100644 --- a/source/slang/slang-ast-serialize.cpp +++ b/source/slang/slang-ast-serialize.cpp @@ -1624,7 +1624,7 @@ SlangResult ASTSerialReader::load(const uint8_t* data, size_t dataCount, ASTBuil { typedef LookupResultItem::Breadcrumb Breadcrumb; - auto breadcrumb = new LookupResultItem::Breadcrumb(Breadcrumb::Kind::Member, DeclRef<Decl>(), nullptr); + auto breadcrumb = new LookupResultItem::Breadcrumb(Breadcrumb::Kind::Member, DeclRef<Decl>(), nullptr, nullptr); m_scope.add(breadcrumb); m_objects[i] = breadcrumb; break; diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index f667c5fc3..39932ea4e 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -1118,7 +1118,7 @@ namespace Slang // `T` is a subtype of some other type `U`, so that // lookup was able to find a member through type `U` // instead. - Constraint, + SuperType, // The lookup process considered a member of an // enclosing type as being in scope, so that any @@ -1154,6 +1154,8 @@ namespace Slang // DeclRef<Decl> declRef; + Val* val = nullptr; + // The next implicit step that the lookup process took to // arrive at a final value. RefPtr<Breadcrumb> next; @@ -1161,11 +1163,13 @@ namespace Slang Breadcrumb( Kind kind, DeclRef<Decl> declRef, + Val* val, RefPtr<Breadcrumb> next, ThisParameterMode thisParameterMode = ThisParameterMode::Default) : kind(kind) , thisParameterMode(thisParameterMode) , declRef(declRef) + , val(val) , next(next) {} }; diff --git a/source/slang/slang-ast-val.cpp b/source/slang/slang-ast-val.cpp index f2c466ba6..76ddb644c 100644 --- a/source/slang/slang-ast-val.cpp +++ b/source/slang/slang-ast-val.cpp @@ -363,7 +363,7 @@ bool TransitiveSubtypeWitness::_equalsValOverride(Val* val) return sub->equals(otherWitness->sub) && sup->equals(otherWitness->sup) && subToMid->equalsVal(otherWitness->subToMid) - && midToSup.equals(otherWitness->midToSup); + && midToSup->equalsVal(otherWitness->midToSup); } Val* TransitiveSubtypeWitness::_substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int * ioDiff) @@ -373,7 +373,7 @@ Val* TransitiveSubtypeWitness::_substituteImplOverride(ASTBuilder* astBuilder, S Type* substSub = as<Type>(sub->substituteImpl(astBuilder, subst, &diff)); Type* substSup = as<Type>(sup->substituteImpl(astBuilder, subst, &diff)); SubtypeWitness* substSubToMid = as<SubtypeWitness>(subToMid->substituteImpl(astBuilder, subst, &diff)); - DeclRef<Decl> substMidToSup = midToSup.substituteImpl(astBuilder, subst, &diff); + SubtypeWitness* substMidToSup = as<SubtypeWitness>(midToSup->substituteImpl(astBuilder, subst, &diff)); // If nothing changed, then we can bail out early. if (!diff) @@ -416,7 +416,7 @@ String TransitiveSubtypeWitness::_toStringOverride() sb << "TransitiveSubtypeWitness("; sb << this->subToMid->toString(); sb << ", "; - sb << this->midToSup.toString(); + sb << this->midToSup->toString(); sb << ")"; return sb.ProduceString(); } @@ -426,7 +426,7 @@ HashCode TransitiveSubtypeWitness::_getHashCodeOverride() auto hash = sub->getHashCode(); hash = combineHash(hash, sup->getHashCode()); hash = combineHash(hash, subToMid->getHashCode()); - hash = combineHash(hash, midToSup.getHashCode()); + hash = combineHash(hash, midToSup->getHashCode()); return hash; } diff --git a/source/slang/slang-ast-val.h b/source/slang/slang-ast-val.h index 547bb303b..bb5bed1bc 100644 --- a/source/slang/slang-ast-val.h +++ b/source/slang/slang-ast-val.h @@ -154,7 +154,7 @@ class TransitiveSubtypeWitness : public SubtypeWitness SubtypeWitness* subToMid = nullptr; // Witness that `mid : sup` - DeclRef<Decl> midToSup; + SubtypeWitness* midToSup = nullptr; // Overrides should be public so base classes can access bool _equalsValOverride(Val* val); @@ -200,4 +200,9 @@ class TaggedUnionSubtypeWitness : public SubtypeWitness Val* _substituteImplOverride(ASTBuilder* astBuilder, SubstitutionSet subst, int* ioDiff); }; +class ThisTypeSubtypeWitness : public SubtypeWitness +{ + SLANG_CLASS(ThisTypeSubtypeWitness) +}; + } // namespace Slang diff --git a/source/slang/slang-check-conformance.cpp b/source/slang/slang-check-conformance.cpp index e1904dc71..25a7ac4ee 100644 --- a/source/slang/slang-check-conformance.cpp +++ b/source/slang/slang-check-conformance.cpp @@ -82,10 +82,15 @@ namespace Slang // where `[...]` represents the "hole" we leave // open to fill in next. // + DeclaredSubtypeWitness* declaredWitness = m_astBuilder->create<DeclaredSubtypeWitness>(); + declaredWitness->sub = bb->sub; + declaredWitness->sup = bb->sup; + declaredWitness->declRef = bb->declRef; + TransitiveSubtypeWitness* transitiveWitness = m_astBuilder->create<TransitiveSubtypeWitness>(); - transitiveWitness->sub = bb->sub; + transitiveWitness->sub = subType; transitiveWitness->sup = bb->sup; - transitiveWitness->midToSup = bb->declRef; + transitiveWitness->midToSup = declaredWitness; // Fill in the current hole, and then set the // hole to point into the node we just created. diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 0de7acae2..39fd7d1dd 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -321,21 +321,43 @@ namespace Slang bb = ConstructDerefExpr(bb, loc); break; - case LookupResultItem::Breadcrumb::Kind::Constraint: + case LookupResultItem::Breadcrumb::Kind::SuperType: { - // TODO: do we need to make something more - // explicit here? - auto expr = ConstructDeclRefExpr( - breadcrumb->declRef, - bb, - loc); - - if(bb && bb->type.isLeftValue) + // Note: a lookup through a super-type can + // occur even in the case of a `static` member, + // so we only modify the base expression here + // if there is one. + // + if( bb ) { - expr->type.isLeftValue = true; - } + // We know that the breadcrumb reprsents a + // cast of the base expression to a super type, + // so we construct that cast explicitly here. + // + auto witness = as<SubtypeWitness>(breadcrumb->val); + SLANG_ASSERT(witness); + auto expr = createCastToSuperTypeExpr(witness->sup, bb, witness); + + // Note that we allow a cast of an l-value to + // be used as an l-value here because it enables + // `[mutating]` methods to be called, and + // mutable properties to be modified, but this + // is probably not *technically* correct, since + // treating an l-value of type `Derived` as + // an l-value of type `Base` implies that we + // can assign an arbitrary value of type `Base` + // to that l-value (which would be an error). + // + // TODO: make sure we believe there are no + // issues here. + // + if(bb && bb->type.isLeftValue) + { + expr->type.isLeftValue = true; + } - bb = expr; + bb = expr; + } } break; diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 0b2c61e18..a4a55c8ce 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -1014,6 +1014,7 @@ namespace Slang ctorItem.breadcrumbs = new LookupResultItem::Breadcrumb( LookupResultItem::Breadcrumb::Kind::Member, typeItem.declRef, + nullptr, typeItem.breadcrumbs); OverloadCandidate candidate; diff --git a/source/slang/slang-lookup.cpp b/source/slang/slang-lookup.cpp index a17ba0ba2..3aab22724 100644 --- a/source/slang/slang-lookup.cpp +++ b/source/slang/slang-lookup.cpp @@ -22,6 +22,7 @@ struct BreadcrumbInfo LookupResultItem::Breadcrumb::Kind kind; LookupResultItem::Breadcrumb::ThisParameterMode thisParameterMode = LookupResultItem::Breadcrumb::ThisParameterMode::Default; DeclRef<Decl> declRef; + Val* val = nullptr; BreadcrumbInfo* prev = nullptr; }; @@ -165,6 +166,7 @@ LookupResultItem CreateLookupResultItem( breadcrumbs = new LookupResultItem::Breadcrumb( bb->kind, bb->declRef, + bb->val, breadcrumbs, bb->thisParameterMode); } @@ -267,33 +269,42 @@ LookupResult lookUpDirectAndTransparentMembers( return result; } - static SubtypeWitness* _makeSubtypeWitness( ASTBuilder* astBuilder, Type* subType, SubtypeWitness* subToMidWitness, Type* superType, - DeclRef<TypeConstraintDecl> midToSuperConstraint) + SubtypeWitness* midtoSuperWitness) { if(subToMidWitness) { TransitiveSubtypeWitness* transitiveWitness = astBuilder->create<TransitiveSubtypeWitness>(); transitiveWitness->subToMid = subToMidWitness; - transitiveWitness->midToSup = midToSuperConstraint; + transitiveWitness->midToSup = midtoSuperWitness; transitiveWitness->sub = subType; transitiveWitness->sup = superType; return transitiveWitness; } else { - DeclaredSubtypeWitness* declaredWitness = astBuilder->create<DeclaredSubtypeWitness>(); - declaredWitness->declRef = midToSuperConstraint; - declaredWitness->sub = subType; - declaredWitness->sup = superType; - return declaredWitness; + return midtoSuperWitness; } } +static SubtypeWitness* _makeSubtypeWitness( + ASTBuilder* astBuilder, + Type* subType, + SubtypeWitness* subToMidWitness, + Type* superType, + DeclRef<TypeConstraintDecl> midToSuperConstraint) +{ + DeclaredSubtypeWitness* midToSuperWitness = astBuilder->create<DeclaredSubtypeWitness>(); + midToSuperWitness->declRef = midToSuperConstraint; + midToSuperWitness->sub = subType; + midToSuperWitness->sup = superType; + return _makeSubtypeWitness(astBuilder, subType, subToMidWitness, superType, midToSuperWitness); +} + // Same as the above, but we are specializing a type instead of a decl-ref static Type* _maybeSpecializeSuperType( ASTBuilder* astBuilder, @@ -337,37 +348,16 @@ static void _lookUpMembersInSuperTypeImpl( LookupResult& ioResult, BreadcrumbInfo* inBreadcrumbs); - static void _lookUpMembersInSuperType( - ASTBuilder* astBuilder, + ASTBuilder* astBuilder, Name* name, Type* leafType, - SubtypeWitness* leafIsIntermediateWitness, - DeclRef<TypeConstraintDecl> intermediateIsSuperConstraint, + Type* superType, + SubtypeWitness* leafIsSuperWitness, LookupRequest const& request, LookupResult& ioResult, BreadcrumbInfo* inBreadcrumbs) { - if( request.semantics ) - { - ensureDecl(request.semantics, intermediateIsSuperConstraint, DeclCheckState::CanUseBaseOfInheritanceDecl); - } - - // The super-type in the constraint (e.g., `Foo` in `T : Foo`) - // will tell us a type we should use for lookup. - // - auto superType = getSup(astBuilder, intermediateIsSuperConstraint); - // - // We will go ahead and perform lookup using `superType`, - // after dealing with some details. - - auto leafIsSuperWitness = _makeSubtypeWitness( - astBuilder, - leafType, - leafIsIntermediateWitness, - superType, - intermediateIsSuperConstraint); - // If we are looking up through an interface type, then // we need to be sure that we add an appropriate // "this type" substitution here, since that needs to @@ -384,8 +374,8 @@ static void _lookUpMembersInSuperType( // BreadcrumbInfo breadcrumb; breadcrumb.prev = inBreadcrumbs; - breadcrumb.kind = LookupResultItem::Breadcrumb::Kind::Constraint; - breadcrumb.declRef = intermediateIsSuperConstraint; + breadcrumb.kind = LookupResultItem::Breadcrumb::Kind::SuperType; + breadcrumb.val = leafIsSuperWitness; breadcrumb.prev = inBreadcrumbs; // TODO: Need to consider case where this might recurse infinitely (e.g., @@ -399,6 +389,39 @@ static void _lookUpMembersInSuperType( _lookUpMembersInSuperTypeImpl(astBuilder, name, leafType, superType, leafIsSuperWitness, request, ioResult, &breadcrumb); } +static void _lookUpMembersInSuperType( + ASTBuilder* astBuilder, + Name* name, + Type* leafType, + SubtypeWitness* leafIsIntermediateWitness, + DeclRef<TypeConstraintDecl> intermediateIsSuperConstraint, + LookupRequest const& request, + LookupResult& ioResult, + BreadcrumbInfo* inBreadcrumbs) +{ + if( request.semantics ) + { + ensureDecl(request.semantics, intermediateIsSuperConstraint, DeclCheckState::CanUseBaseOfInheritanceDecl); + } + + // The super-type in the constraint (e.g., `Foo` in `T : Foo`) + // will tell us a type we should use for lookup. + // + auto superType = getSup(astBuilder, intermediateIsSuperConstraint); + // + // We will go ahead and perform lookup using `superType`, + // after dealing with some details. + + auto leafIsSuperWitness = _makeSubtypeWitness( + astBuilder, + leafType, + leafIsIntermediateWitness, + superType, + intermediateIsSuperConstraint); + + return _lookUpMembersInSuperType(astBuilder, name, leafType, superType, leafIsSuperWitness, request, ioResult, inBreadcrumbs); +} + static void _lookUpMembersInSuperTypeDeclImpl( ASTBuilder* astBuilder, Name* name, @@ -587,10 +610,32 @@ static void _lookUpMembersInSuperTypeImpl( _lookUpMembersInSuperTypeDeclImpl(astBuilder, name, leafType, superType, leafIsSuperWitness, declRef, request, ioResult, inBreadcrumbs); } - if (auto extractExistentialType = as<ExtractExistentialType>(superType)) + else if (auto extractExistentialType = as<ExtractExistentialType>(superType)) { _lookUpMembersInSuperTypeDeclImpl(astBuilder, name, leafType, superType, leafIsSuperWitness, extractExistentialType->interfaceDeclRef, request, ioResult, inBreadcrumbs); } + else if( auto thisType = as<ThisType>(superType) ) + { + // We need to create a witness that represents the next link in the + // chain. The `leafIsSuperWitness` represents the knowledge that `leafType : superType` + // (and we know that `superType == thisType`, but we now need to extend that + // with the knowledge that `thisType : thisType->interfaceTypeDeclRef`. + // + auto interfaceType = DeclRefType::create(astBuilder, thisType->interfaceDeclRef); + + auto superIsInterfaceWitness = astBuilder->create<ThisTypeSubtypeWitness>(); + superIsInterfaceWitness->sub = superType; + superIsInterfaceWitness->sup = interfaceType; + + auto leafIsInterfaceWitness = _makeSubtypeWitness( + astBuilder, + leafType, + leafIsSuperWitness, + interfaceType, + superIsInterfaceWitness); + + _lookUpMembersInSuperTypeDeclImpl(astBuilder, name, leafType, interfaceType, leafIsInterfaceWitness, thisType->interfaceDeclRef, request, ioResult, inBreadcrumbs); + } } /// Perform lookup for `name` in the context of `type`. diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index f756cf28a..2f1511444 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -1142,12 +1142,19 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower // that is itself an interface conformance, so the result // of lowering this value should be a "key" that we can // use to look up a witness table. - IRInst* requirementKey = getInterfaceRequirementKey(context, val->midToSup.getDecl()); - + // // TODO: There are some ugly cases here if `midToSup` is allowed // to be an arbitrary witness, rather than just a declared one, - // and we should probably change the front-end representation - // to reflect the right constraints. + // and we probably need to change the logic here so that we + // instead think in terms of applying a subtype witness to + // either a value or a witness table, to perform the appropriate + // casting/lookup logic. + // + // For now we rely on the fact that the front-end doesn't + // produce transitive witnesses in shapes that will cuase us + // problems here. + // + IRInst* requirementKey = lowerSimpleVal(context, val->midToSup); return LoweredValInfo::simple(getBuilder()->emitLookupInterfaceMethodInst( getBuilder()->getWitnessTableType(lowerType(context, val->sup)), @@ -2671,7 +2678,10 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> LoweredValInfo visitMemberExpr(MemberExpr* expr) { auto loweredType = lowerType(context, expr->type); - auto loweredBase = lowerSubExpr(expr->baseExpression); + + auto baseExpr = expr->baseExpression; + baseExpr = maybeIgnoreCastToInterface(baseExpr); + auto loweredBase = lowerSubExpr(baseExpr); auto declRef = expr->declRef; if (auto fieldDeclRef = declRef.as<VarDecl>()) @@ -2687,31 +2697,6 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> boundMemberInfo->declRef = callableDeclRef; return LoweredValInfo::boundMember(boundMemberInfo); } - else if(auto constraintDeclRef = declRef.as<TypeConstraintDecl>()) - { - auto superType = getSup(getASTBuilder(), constraintDeclRef); - if(auto superDeclRefType = as<DeclRefType>(superType)) - { - if(auto superStructDeclRef = superDeclRefType->declRef.template as<StructDecl>()) - { - // The constraint is saying that the given type inherits - // from a concrete `struct` type, which means it should - // be satisfied by a witness that represents a field - // (TODO: or a chain of fields) to fetch to get the - // final value. - // - return extractField(loweredType, loweredBase, constraintDeclRef); - } - } - - // The code is making use of a "witness" that a value of - // some generic type conforms to an interface. - // - // For now we will just emit the base expression as-is. - // TODO: we may need to insert an explicit instruction - // for a cast here (that could become a no-op later). - return loweredBase; - } else if(auto propertyDeclRef = declRef.as<PropertyDecl>()) { // A reference to a property is a special case, because @@ -3187,6 +3172,24 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> } } + /// Return `expr` with any outer casts to interface types stripped away + Expr* maybeIgnoreCastToInterface(Expr* expr) + { + auto e = expr; + while( auto castExpr = as<CastToSuperTypeExpr>(e) ) + { + if(auto declRefType = as<DeclRefType>(e->type)) + { + if(declRefType->declRef.as<InterfaceDecl>()) + { + e = castExpr->valueArg; + continue; + } + } + break; + } + return e; + } LoweredValInfo visitInvokeExpr(InvokeExpr* expr) { @@ -3274,6 +3277,12 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo> // a member function: if( baseExpr ) { + // The base expression might be an "upcast" to a base interface, in + // which case we don't want to emit the result of the cast, but instead + // the source. + // + baseExpr = maybeIgnoreCastToInterface(baseExpr); + auto thisType = getThisParamTypeForCallable(context, funcDeclRef); auto irThisType = lowerType(context, thisType); addCallArgsForParam( |
