diff options
Diffstat (limited to 'source/slang/slang-check-expr.cpp')
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 118 |
1 files changed, 113 insertions, 5 deletions
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 2290936d8..317ab6a1a 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -25,6 +25,31 @@ namespace Slang return as<DeclRefType>(expr->type); } + void SemanticsContext::ExprLocalScope::addBinding(LetExpr* binding) + { + if (!m_innerMostBinding) + { + SLANG_ASSERT(!m_outerMostBinding); + + // If we haven't added any bindings, then `binding` + // becomes both the inner-most and outer most. + // + m_innerMostBinding = binding; + m_outerMostBinding = binding; + } + else + { + SLANG_ASSERT(m_outerMostBinding); + + // If we already have bindings, then `binding` + // will become the new inner-most binding. + // + m_innerMostBinding->body = binding; + m_innerMostBinding = binding; + } + } + + /// Move `expr` into a temporary variable and execute `func` on that variable. /// /// Returns an expression that wraps both the creation and initialization of @@ -46,11 +71,30 @@ namespace Slang letExpr->decl = varDecl; auto body = func(varDeclRef); + Expr* result = body; + if (auto exprLocalScope = getExprLocalScope()) + { + // We want to add the `LetExpr` to the set of such expressions + // in the local scope, so that it can be emitted properly. + // + exprLocalScope->addBinding(letExpr); + } + else + { + // If we somehow got in here and there wasn't an expression-local + // scope established yet, it almost certainly represents an error. + // + SLANG_ASSERT(exprLocalScope); - letExpr->body = body; - letExpr->type = body->type; + // As a fallback, though, we will try to wire up the `letExpr` + // to surround the body directly and return that. + // + letExpr->body = body; + letExpr->type = body->type; - return letExpr; + result = letExpr; + } + return result; } /// Execute `func` on a variable with the value of `expr`. @@ -62,6 +106,11 @@ namespace Slang template<typename F> Expr* SemanticsVisitor::maybeMoveTemp(Expr* const& expr, F const& func) { + // TODO: Eventually this operation could consider any case where the + // input `expr` names an immutable "path": one that starts at an + // immutable binding and follows a (possibly empty) chain of accesses + // to immutable members. + if(auto varExpr = as<VarExpr>(expr)) { auto declRef = varExpr->declRef; @@ -114,6 +163,26 @@ namespace Slang openedValue->declRef = varDeclRef; openedValue->type = QualType(openedType); + // The result of opening an existential is an l-value + // if the original existential is an l-value. + // + if(expr->type.isLeftValue) + { + // Marking the opened value as an l-value is the easy part. + // + openedValue->type.isLeftValue = true; + + // The more challenging bit is that in this case the `maybeMoveTemp()` + // operation will have copied the original existential value into + // a temporary. + // + // If this expression is used in an l-value context, then we need + // to be able to generate code to "write back" the modified value + // (which will be of `openedType`) to the original location named + // by `expr` (an existential for `interfaceDeclRef`). + // + } + return openedValue; }); } @@ -606,8 +675,47 @@ namespace Slang { if (!term) return nullptr; - SemanticsExprVisitor exprVisitor(getShared()); - return exprVisitor.dispatch(term); + // The process of checking a term/expression can end up introducing + // temporaries that need to be added to an outer scope. When jumping + // into expression checking, we want to check if we already have such + // a scope in place. If we do, we will re-use it for any sub-expressions. + // If not, we need to create one. + // + if(getExprLocalScope()) + { + return dispatchExpr(term, *this); + } + + ExprLocalScope exprLocalScope; + + Expr* checkedTerm = dispatchExpr(term, withExprLocalScope(&exprLocalScope)); + + LetExpr* outerMostBinding = exprLocalScope.getOuterMostBinding(); + if(!outerMostBinding) + { + return checkedTerm; + } + + LetExpr* binding = outerMostBinding; + auto type = checkedTerm->type; + while (binding) + { + binding->type = type; + + if (auto body = binding->body) + { + binding = as<LetExpr>(binding->body); + SLANG_ASSERT(binding); + continue; + } + else + { + binding->body = checkedTerm; + break; + } + } + + return outerMostBinding; } Expr* SemanticsVisitor::CreateErrorExpr(Expr* expr) |
