summaryrefslogtreecommitdiff
path: root/source/slang
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/slang-ast-serialize.cpp2
-rw-r--r--source/slang/slang-ast-support-types.h6
-rw-r--r--source/slang/slang-ast-val.cpp8
-rw-r--r--source/slang/slang-ast-val.h7
-rw-r--r--source/slang/slang-check-conformance.cpp9
-rw-r--r--source/slang/slang-check-expr.cpp46
-rw-r--r--source/slang/slang-check-overload.cpp1
-rw-r--r--source/slang/slang-lookup.cpp115
-rw-r--r--source/slang/slang-lower-to-ir.cpp69
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(