summaryrefslogtreecommitdiffstats
path: root/source/slang/lookup.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2018-04-11 16:18:29 -0700
committerGitHub <noreply@github.com>2018-04-11 16:18:29 -0700
commitbaf194e7456ba4568dcf11249896af35b3ce18cc (patch)
treef75e20db450100d41bfa9c384a8bab0fdc28a749 /source/slang/lookup.cpp
parent6322983fa4dc84ef1e9dd8fad54d4c1580436e67 (diff)
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<T,N>` 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
Diffstat (limited to 'source/slang/lookup.cpp')
-rw-r--r--source/slang/lookup.cpp203
1 files changed, 171 insertions, 32 deletions
diff --git a/source/slang/lookup.cpp b/source/slang/lookup.cpp
index eebef6503..2735bc6ba 100644
--- a/source/slang/lookup.cpp
+++ b/source/slang/lookup.cpp
@@ -222,6 +222,67 @@ void DoMemberLookupImpl(
name, baseType, request, ioResult, breadcrumbs);
}
+// If we are about to perform lookup through an interface, then
+// we need to specialize the decl-ref to that interface to include
+// a "this type" subtitution. This function applies that substition
+// when it is required, and returns the existing `declRef` otherwise.
+DeclRef<Decl> maybeSpecializeInterfaceDeclRef(
+ RefPtr<Type> subType,
+ RefPtr<Type> superType,
+ DeclRef<Decl> superTypeDeclRef, // The decl-ref we are going to perform lookup in
+ DeclRef<TypeConstraintDecl> constraintDeclRef) // The type constraint that told us our type is a subtype
+{
+ if (auto superInterfaceDeclRef = superTypeDeclRef.As<InterfaceDecl>())
+ {
+ // Create a subtype witness value to note the subtype relationship
+ // that makes this specialization valid.
+ //
+ // Note: this is to ensure that we can specialize the subtype witness
+ // later (e.g., by replacing a subtype witness that represents a generic
+ // constraint paraqmeter with the concrete generic arguments that
+ // are used at a particular call site to the generic).
+ RefPtr<DeclaredSubtypeWitness> subtypeWitness = new DeclaredSubtypeWitness();
+ subtypeWitness->declRef = constraintDeclRef;
+ subtypeWitness->sub = subType;
+ subtypeWitness->sup = superType;
+
+ RefPtr<ThisTypeSubstitution> thisTypeSubst = new ThisTypeSubstitution();
+ thisTypeSubst->interfaceDecl = superInterfaceDeclRef.getDecl();
+ thisTypeSubst->witness = subtypeWitness;
+ thisTypeSubst->outer = superInterfaceDeclRef.substitutions.substitutions;
+
+ auto specializedInterfaceDeclRef = DeclRef<Decl>(superInterfaceDeclRef.getDecl(), thisTypeSubst);
+ return specializedInterfaceDeclRef;
+ }
+
+ return superTypeDeclRef;
+}
+
+// Same as the above, but we are specializing a type instead of a decl-ref
+RefPtr<Type> maybeSpecializeInterfaceDeclRef(
+ Session* session,
+ RefPtr<Type> subType,
+ RefPtr<Type> superType, // The type we are going to perform lookup in
+ DeclRef<TypeConstraintDecl> constraintDeclRef) // The type constraint that told us our type is a subtype
+{
+ if (auto superDeclRefType = superType->As<DeclRefType>())
+ {
+ if (auto superInterfaceDeclRef = superDeclRefType->declRef.As<InterfaceDecl>())
+ {
+ auto specializedInterfaceDeclRef = maybeSpecializeInterfaceDeclRef(
+ subType,
+ superType,
+ superInterfaceDeclRef,
+ constraintDeclRef);
+ auto specializedInterfaceType = DeclRefType::Create(session, specializedInterfaceDeclRef);
+ return specializedInterfaceType;
+ }
+ }
+
+ return superType;
+}
+
+
// Look for members of the given name in the given container for declarations
void DoLocalLookupImpl(
Session* session,
@@ -313,27 +374,53 @@ void DoLocalLookupImpl(
// for interface decls, also lookup in the base interfaces
if (request.semantics)
{
- bool isInterface = containerDeclRef.As<InterfaceDecl>() ? true : false;
+ // TODO:
+ // The logic here is a bit gross, because it tries to work in terms of
+ // decl-refs instead of types (e.g., it asserts that the target type
+ // for an `extension` declaration must be a decl-ref type).
+ //
+ // This code should be converted to do a type-based lookup
+ // through declared bases for *any* aggregate type declaration.
+ // I think that logic is present in the type-bsed lookup path, but
+ // it would be needed here for when doing lookup from inside an
+ // aggregate declaration.
+
// if we are looking at an extension, find the target decl that we are extending
+ DeclRef<Decl> targetDeclRef = containerDeclRef;
+ RefPtr<DeclRefType> targetDeclRefType;
if (auto extDeclRef = containerDeclRef.As<ExtensionDecl>())
{
- auto targetDeclRefType = extDeclRef.getDecl()->targetType->AsDeclRefType();
+ targetDeclRefType = extDeclRef.getDecl()->targetType->AsDeclRefType();
SLANG_ASSERT(targetDeclRefType);
int diff = 0;
- auto targetDeclRef = targetDeclRefType->declRef.As<ContainerDecl>().SubstituteImpl(containerDeclRef.substitutions, &diff);
- isInterface = targetDeclRef.As<InterfaceDecl>() ? true : false;
+ targetDeclRef = targetDeclRefType->declRef.As<ContainerDecl>().SubstituteImpl(containerDeclRef.substitutions, &diff);
}
+
// if we are looking inside an interface decl, try find in the interfaces it inherits from
+ bool isInterface = targetDeclRef.As<InterfaceDecl>() ? true : false;
if (isInterface)
{
+ if(!targetDeclRefType)
+ {
+ targetDeclRefType = DeclRefType::Create(session, targetDeclRef);
+ }
+
auto baseInterfaces = getMembersOfType<InheritanceDecl>(containerDeclRef);
for (auto inheritanceDeclRef : baseInterfaces)
{
checkDecl(request.semantics, inheritanceDeclRef.decl);
+
auto baseType = inheritanceDeclRef.getDecl()->base.type.As<DeclRefType>();
SLANG_ASSERT(baseType);
int diff = 0;
auto baseInterfaceDeclRef = baseType->declRef.SubstituteImpl(containerDeclRef.substitutions, &diff);
+
+ baseInterfaceDeclRef = maybeSpecializeInterfaceDeclRef(
+ targetDeclRefType,
+ baseType,
+ baseInterfaceDeclRef,
+ inheritanceDeclRef);
+
DoLocalLookupImpl(session, name, baseInterfaceDeclRef.As<ContainerDecl>(), request, result, inBreadcrumbs);
}
}
@@ -463,6 +550,68 @@ void lookUpMemberImpl(
Type* type,
LookupResult& ioResult,
BreadcrumbInfo* inBreadcrumbs,
+ LookupMask mask);
+
+// Perform lookup "through" the given constraint decl-ref,
+// which should show that `subType` is a sub-type of some
+// super-type (e.g., an interface).
+//
+void lookUpThroughConstraint(
+ Session* session,
+ SemanticsVisitor* semantics,
+ Name* name,
+ Type* subType,
+ DeclRef<TypeConstraintDecl> constraintDeclRef,
+ LookupResult& ioResult,
+ BreadcrumbInfo* inBreadcrumbs,
+ LookupMask mask)
+{
+ // 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(constraintDeclRef);
+ //
+ // We will go ahead and perform lookup using `superType`,
+ // after dealing with some details.
+
+ // 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
+ // be applied to any members we look up.
+ //
+ superType = maybeSpecializeInterfaceDeclRef(
+ session,
+ subType,
+ superType,
+ constraintDeclRef);
+
+ // We need to track the indirection we took in lookup,
+ // so that we can construct an approrpiate AST on the other
+ // side that includes the "upcase" from sub-type to super-type.
+ //
+ BreadcrumbInfo breadcrumb;
+ breadcrumb.prev = inBreadcrumbs;
+ breadcrumb.kind = LookupResultItem::Breadcrumb::Kind::Constraint;
+ breadcrumb.declRef = constraintDeclRef;
+
+ // TODO: Need to consider case where this might recurse infinitely (e.g.,
+ // if an inheritance clause does something like `Bad<T> : Bad<Bad<T>>`.
+ //
+ // TODO: The even simpler thing we need to worry about here is that if
+ // there is ever a "diamond" relationship in the inheritance hierarchy,
+ // we might end up seeing the same interface via diffrent "paths" and
+ // we wouldn't want that to lead to overload-resolution failure.
+ //
+ lookUpMemberImpl(session, semantics, name, superType, ioResult, &breadcrumb, mask);
+}
+
+void lookUpMemberImpl(
+ Session* session,
+ SemanticsVisitor* semantics,
+ Name* name,
+ Type* type,
+ LookupResult& ioResult,
+ BreadcrumbInfo* inBreadcrumbs,
LookupMask mask)
{
if (auto declRefType = type->As<DeclRefType>())
@@ -472,20 +621,15 @@ void lookUpMemberImpl(
{
for (auto constraintDeclRef : getMembersOfType<TypeConstraintDecl>(declRef.As<ContainerDecl>()))
{
- // The super-type in the constraint (e.g., `Foo` in `T : Foo`)
- // will tell us a type we should use for lookup.
- auto bound = GetSup(constraintDeclRef);
-
- // Go ahead and use the target type, with an appropriate breadcrumb
- // to indicate that we indirected through a type constraint.
-
- BreadcrumbInfo breadcrumb;
- breadcrumb.prev = inBreadcrumbs;
- breadcrumb.kind = LookupResultItem::Breadcrumb::Kind::Constraint;
- breadcrumb.declRef = constraintDeclRef;
-
- // TODO: Need to consider case where this might recurse infinitely.
- lookUpMemberImpl(session, semantics, name, bound, ioResult, &breadcrumb, mask);
+ lookUpThroughConstraint(
+ session,
+ semantics,
+ name,
+ type,
+ constraintDeclRef,
+ ioResult,
+ inBreadcrumbs,
+ mask);
}
}
else if (auto aggTypeDeclRef = declRef.As<AggTypeDecl>())
@@ -514,20 +658,15 @@ void lookUpMemberImpl(
if(!subDeclRefType->declRef.Equals(genericTypeParamDeclRef))
continue;
- // The super-type in the constraint (e.g., `Foo` in `T : Foo`)
- // will tell us a type we should use for lookup.
- auto bound = GetSup(constraintDeclRef);
-
- // Go ahead and use the target type, with an appropriate breadcrumb
- // to indicate that we indirected through a type constraint.
-
- BreadcrumbInfo breadcrumb;
- breadcrumb.prev = inBreadcrumbs;
- breadcrumb.kind = LookupResultItem::Breadcrumb::Kind::Constraint;
- breadcrumb.declRef = constraintDeclRef;
-
- // TODO: Need to consider case where this might recurse infinitely.
- lookUpMemberImpl(session, semantics, name, bound, ioResult, &breadcrumb, mask);
+ lookUpThroughConstraint(
+ session,
+ semantics,
+ name,
+ type,
+ constraintDeclRef,
+ ioResult,
+ inBreadcrumbs,
+ mask);
}
}