summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-check-expr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-check-expr.cpp')
-rw-r--r--source/slang/slang-check-expr.cpp110
1 files changed, 105 insertions, 5 deletions
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index 9aa081e1b..f1c1b9a43 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -379,14 +379,77 @@ namespace Slang
}
}
- RefPtr<Expr> SemanticsVisitor::ResolveOverloadedExpr(RefPtr<OverloadedExpr> overloadedExpr, LookupMask mask)
+ LookupResult SemanticsVisitor::resolveOverloadedLookup(LookupResult const& inResult)
+ {
+ // If the result isn't actually overloaded, it is fine as-is
+ if (!inResult.isValid()) return inResult;
+ if (!inResult.isOverloaded()) return inResult;
+
+ // We are going to build up a list of items to return.
+ List<LookupResultItem> items;
+ for( auto item : inResult.items )
+ {
+ // For each item we consider adding, we will compare it
+ // to those items we've already added.
+ //
+ // If any of the existing items is "better" than `item`,
+ // then we will skip adding `item`.
+ //
+ // If `item` is "better" than any of the existing items,
+ // we will remove those from `items`.
+ //
+ bool shouldAdd = true;
+ for( Index ii = 0; ii < items.getCount(); ++ii )
+ {
+ int cmp = CompareLookupResultItems(item, items[ii]);
+ if( cmp < 0 )
+ {
+ // The new `item` is strictly better
+ items.fastRemoveAt(ii);
+ --ii;
+ }
+ else if( cmp > 0 )
+ {
+ // The existing item is strictly better
+ shouldAdd = false;
+ }
+ }
+ if( shouldAdd )
+ {
+ items.add(item);
+ }
+ }
+
+ // The resulting `items` list should be all those items
+ // that were neither better nor worse than one another.
+ //
+ // There should always be at least one such item.
+ //
+ SLANG_ASSERT(items.getCount() != 0);
+
+ LookupResult result;
+ for( auto item : items )
+ {
+ AddToLookupResult(result, item);
+ }
+ return result;
+ }
+
+ RefPtr<Expr> SemanticsVisitor::_resolveOverloadedExprImpl(RefPtr<OverloadedExpr> overloadedExpr, LookupMask mask, DiagnosticSink* diagSink)
{
auto lookupResult = overloadedExpr->lookupResult2;
SLANG_RELEASE_ASSERT(lookupResult.isValid() && lookupResult.isOverloaded());
// Take the lookup result we had, and refine it based on what is expected in context.
+ //
+ // E.g., if there is both a type and a variable named `Foo`, but in context we know
+ // that a type is expected, then we can disambiguate by assuming the type is intended.
+ //
lookupResult = refineLookup(lookupResult, mask);
+ // Try to filter out overload candidates based on which ones are "better" than one another.
+ lookupResult = resolveOverloadedLookup(lookupResult);
+
if (!lookupResult.isValid())
{
// If we didn't find any symbols after filtering, then just
@@ -394,9 +457,23 @@ namespace Slang
return overloadedExpr;
}
- if (lookupResult.isOverloaded())
+ if(!lookupResult.isOverloaded())
+ {
+ // If there is only a single item left in the lookup result,
+ // then we can proceed to use that item alone as the resolved
+ // expression.
+ //
+ return ConstructLookupResultExpr(lookupResult.item, overloadedExpr->base, overloadedExpr->loc);
+ }
+
+ // Otherwise, we weren't able to resolve the overloading given
+ // the information available in context.
+ //
+ // If the client is asking for us to emit diagnostics about
+ // this fact, we should do so here:
+ //
+ if( diagSink )
{
- // We had an ambiguity anyway, so report it.
getSink()->diagnose(overloadedExpr, Diagnostics::ambiguousReference, lookupResult.items[0].declRef.GetName());
for(auto item : lookupResult.items)
@@ -408,9 +485,32 @@ namespace Slang
// TODO(tfoley): should we construct a new ErrorExpr here?
return CreateErrorExpr(overloadedExpr);
}
+ else
+ {
+ // If the client isn't trying to *force* overload resolution
+ // to complete just yet (e.g., they are just trying out one
+ // candidate for an overloaded call site), then we return
+ // the input expression as-is.
+ //
+ return overloadedExpr;
+ }
+ }
+
+ RefPtr<Expr> SemanticsVisitor::maybeResolveOverloadedExpr(RefPtr<Expr> expr, LookupMask mask, DiagnosticSink* diagSink)
+ {
+ if( auto overloadedExpr = as<OverloadedExpr>(expr) )
+ {
+ return _resolveOverloadedExprImpl(overloadedExpr, mask, diagSink);
+ }
+ else
+ {
+ return expr;
+ }
+ }
- // otherwise, we had a single decl and it was valid, hooray!
- return ConstructLookupResultExpr(lookupResult.item, overloadedExpr->base, overloadedExpr->loc);
+ RefPtr<Expr> SemanticsVisitor::resolveOverloadedExpr(RefPtr<OverloadedExpr> overloadedExpr, LookupMask mask)
+ {
+ return _resolveOverloadedExprImpl(overloadedExpr, mask, getSink());
}
RefPtr<Expr> SemanticsVisitor::CheckTerm(RefPtr<Expr> term)