implements PR-13.1
This commit is contained in:
parent
df0d9f4601
commit
f8f520d284
@ -33,11 +33,16 @@ final class PbsFlowBodyAnalyzer {
|
||||
validateCallableBody(
|
||||
functionDecl.parameters(),
|
||||
functionDecl.body(),
|
||||
typeOps.callableReturnType(functionDecl.returnKind(), functionDecl.returnType(), functionDecl.resultErrorType(), model),
|
||||
functionDecl.resultErrorType() == null ? null : functionDecl.resultErrorType().name(),
|
||||
null,
|
||||
model,
|
||||
diagnostics);
|
||||
newCallableContext(
|
||||
typeOps.callableReturnType(
|
||||
functionDecl.returnKind(),
|
||||
functionDecl.returnType(),
|
||||
functionDecl.resultErrorType(),
|
||||
model),
|
||||
functionDecl.resultErrorType() == null ? null : functionDecl.resultErrorType().name(),
|
||||
null,
|
||||
model,
|
||||
diagnostics));
|
||||
continue;
|
||||
}
|
||||
if (topDecl instanceof PbsAst.StructDecl structDecl) {
|
||||
@ -46,21 +51,27 @@ final class PbsFlowBodyAnalyzer {
|
||||
validateCallableBody(
|
||||
method.parameters(),
|
||||
method.body(),
|
||||
typeOps.callableReturnType(method.returnKind(), method.returnType(), method.resultErrorType(), model),
|
||||
method.resultErrorType() == null ? null : method.resultErrorType().name(),
|
||||
receiverType,
|
||||
model,
|
||||
diagnostics);
|
||||
newCallableContext(
|
||||
typeOps.callableReturnType(
|
||||
method.returnKind(),
|
||||
method.returnType(),
|
||||
method.resultErrorType(),
|
||||
model),
|
||||
method.resultErrorType() == null ? null : method.resultErrorType().name(),
|
||||
receiverType,
|
||||
model,
|
||||
diagnostics));
|
||||
}
|
||||
for (final var ctor : structDecl.ctors()) {
|
||||
validateCallableBody(
|
||||
ctor.parameters(),
|
||||
ctor.body(),
|
||||
TypeView.unit(),
|
||||
null,
|
||||
receiverType,
|
||||
model,
|
||||
diagnostics);
|
||||
newCallableContext(
|
||||
TypeView.unit(),
|
||||
null,
|
||||
receiverType,
|
||||
model,
|
||||
diagnostics));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -70,37 +81,57 @@ final class PbsFlowBodyAnalyzer {
|
||||
validateCallableBody(
|
||||
method.parameters(),
|
||||
method.body(),
|
||||
typeOps.callableReturnType(method.returnKind(), method.returnType(), method.resultErrorType(), model),
|
||||
method.resultErrorType() == null ? null : method.resultErrorType().name(),
|
||||
receiverType,
|
||||
model,
|
||||
diagnostics);
|
||||
newCallableContext(
|
||||
typeOps.callableReturnType(
|
||||
method.returnKind(),
|
||||
method.returnType(),
|
||||
method.resultErrorType(),
|
||||
model),
|
||||
method.resultErrorType() == null ? null : method.resultErrorType().name(),
|
||||
receiverType,
|
||||
model,
|
||||
diagnostics));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateCallableBody(
|
||||
final ReadOnlyList<PbsAst.Parameter> parameters,
|
||||
final PbsAst.Block body,
|
||||
private PbsFlowBodyContext newCallableContext(
|
||||
final TypeView returnType,
|
||||
final String resultErrorName,
|
||||
final TypeView receiverType,
|
||||
final Model model,
|
||||
final DiagnosticSink diagnostics) {
|
||||
final var scope = new Scope();
|
||||
return new PbsFlowBodyContext(
|
||||
new Scope(),
|
||||
returnType,
|
||||
resultErrorName,
|
||||
receiverType,
|
||||
model,
|
||||
diagnostics);
|
||||
}
|
||||
|
||||
private void validateCallableBody(
|
||||
final ReadOnlyList<PbsAst.Parameter> parameters,
|
||||
final PbsAst.Block body,
|
||||
final PbsFlowBodyContext context) {
|
||||
final var scope = context.scope();
|
||||
for (final var parameter : parameters) {
|
||||
scope.bind(parameter.name(), typeOps.typeFromTypeRef(parameter.typeRef(), model, receiverType));
|
||||
scope.bind(
|
||||
parameter.name(),
|
||||
typeOps.typeFromTypeRef(parameter.typeRef(), context.model(), context.receiverType()));
|
||||
}
|
||||
analyzeBlock(body, scope, returnType, resultErrorName, receiverType, model, diagnostics, true);
|
||||
validateCallableCompletion(body, returnType, model, diagnostics);
|
||||
final var callableContext = context.withScope(scope);
|
||||
analyzeBlock(body, callableContext, true);
|
||||
validateCallableCompletion(body, callableContext);
|
||||
}
|
||||
|
||||
private void validateCallableCompletion(
|
||||
final PbsAst.Block body,
|
||||
final TypeView returnType,
|
||||
final Model model,
|
||||
final DiagnosticSink diagnostics) {
|
||||
final PbsFlowBodyContext context) {
|
||||
final var returnType = context.returnType();
|
||||
final var model = context.model();
|
||||
final var diagnostics = context.diagnostics();
|
||||
final var returnKind = returnType.kind();
|
||||
final var enforceResultCompletion = returnKind == Kind.RESULT;
|
||||
final var enforcePlainNonUnitCompletion = returnKind != Kind.RESULT
|
||||
@ -285,9 +316,26 @@ final class PbsFlowBodyAnalyzer {
|
||||
final Model model,
|
||||
final DiagnosticSink diagnostics,
|
||||
final boolean valueContext) {
|
||||
final var scope = outerScope.copy();
|
||||
return analyzeBlock(
|
||||
block,
|
||||
new PbsFlowBodyContext(
|
||||
outerScope,
|
||||
returnType,
|
||||
resultErrorName,
|
||||
receiverType,
|
||||
model,
|
||||
diagnostics),
|
||||
valueContext);
|
||||
}
|
||||
|
||||
private TypeView analyzeBlock(
|
||||
final PbsAst.Block block,
|
||||
final PbsFlowBodyContext context,
|
||||
final boolean valueContext) {
|
||||
final var scope = context.scope().copy();
|
||||
final var scopedContext = context.withScope(scope);
|
||||
for (final var statement : block.statements()) {
|
||||
analyzeStatement(statement, scope, returnType, resultErrorName, receiverType, model, diagnostics);
|
||||
analyzeStatement(statement, scopedContext);
|
||||
}
|
||||
if (block.tailExpression() == null) {
|
||||
return TypeView.unit();
|
||||
@ -296,11 +344,11 @@ final class PbsFlowBodyAnalyzer {
|
||||
block.tailExpression(),
|
||||
scope,
|
||||
null,
|
||||
returnType,
|
||||
resultErrorName,
|
||||
receiverType,
|
||||
model,
|
||||
diagnostics,
|
||||
context.returnType(),
|
||||
context.resultErrorName(),
|
||||
context.receiverType(),
|
||||
context.model(),
|
||||
context.diagnostics(),
|
||||
ExprUse.VALUE,
|
||||
valueContext,
|
||||
this::analyzeBlock).type();
|
||||
@ -308,12 +356,13 @@ final class PbsFlowBodyAnalyzer {
|
||||
|
||||
private void analyzeStatement(
|
||||
final PbsAst.Statement statement,
|
||||
final Scope scope,
|
||||
final TypeView returnType,
|
||||
final String resultErrorName,
|
||||
final TypeView receiverType,
|
||||
final Model model,
|
||||
final DiagnosticSink diagnostics) {
|
||||
final PbsFlowBodyContext context) {
|
||||
final var scope = context.scope();
|
||||
final var returnType = context.returnType();
|
||||
final var resultErrorName = context.resultErrorName();
|
||||
final var receiverType = context.receiverType();
|
||||
final var model = context.model();
|
||||
final var diagnostics = context.diagnostics();
|
||||
if (statement instanceof PbsAst.LetStatement letStatement) {
|
||||
final var expected = letStatement.explicitType() == null
|
||||
? null
|
||||
@ -335,14 +384,7 @@ final class PbsFlowBodyAnalyzer {
|
||||
}
|
||||
if (statement instanceof PbsAst.ReturnStatement returnStatement) {
|
||||
if (returnStatement.value() != null) {
|
||||
analyzeReturnStatement(
|
||||
returnStatement.value(),
|
||||
scope,
|
||||
returnType,
|
||||
resultErrorName,
|
||||
receiverType,
|
||||
model,
|
||||
diagnostics);
|
||||
analyzeReturnStatement(returnStatement.value(), context);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -365,12 +407,12 @@ final class PbsFlowBodyAnalyzer {
|
||||
"If statement condition must have bool type",
|
||||
ifStatement.condition().span());
|
||||
}
|
||||
analyzeBlock(ifStatement.thenBlock(), scope, returnType, resultErrorName, receiverType, model, diagnostics, false);
|
||||
analyzeBlock(ifStatement.thenBlock(), context, false);
|
||||
if (ifStatement.elseBlock() != null) {
|
||||
analyzeBlock(ifStatement.elseBlock(), scope, returnType, resultErrorName, receiverType, model, diagnostics, false);
|
||||
analyzeBlock(ifStatement.elseBlock(), context, false);
|
||||
}
|
||||
if (ifStatement.elseIf() != null) {
|
||||
analyzeStatement(ifStatement.elseIf(), scope, returnType, resultErrorName, receiverType, model, diagnostics);
|
||||
analyzeStatement(ifStatement.elseIf(), context);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -432,7 +474,7 @@ final class PbsFlowBodyAnalyzer {
|
||||
}
|
||||
final var bodyScope = scope.copy();
|
||||
bodyScope.bind(iteratorName, iteratorType);
|
||||
analyzeBlock(body, bodyScope, returnType, resultErrorName, receiverType, model, diagnostics, false);
|
||||
analyzeBlock(body, context.withScope(bodyScope), false);
|
||||
return;
|
||||
}
|
||||
if (statement instanceof PbsAst.WhileStatement whileStatement) {
|
||||
@ -454,7 +496,7 @@ final class PbsFlowBodyAnalyzer {
|
||||
"While condition must have bool type",
|
||||
whileStatement.condition().span());
|
||||
}
|
||||
analyzeBlock(whileStatement.body(), scope, returnType, resultErrorName, receiverType, model, diagnostics, false);
|
||||
analyzeBlock(whileStatement.body(), context, false);
|
||||
return;
|
||||
}
|
||||
if (statement instanceof PbsAst.ExpressionStatement expressionStatement) {
|
||||
@ -473,36 +515,31 @@ final class PbsFlowBodyAnalyzer {
|
||||
return;
|
||||
}
|
||||
if (statement instanceof PbsAst.AssignStatement assignStatement) {
|
||||
analyzeAssignmentStatement(assignStatement, scope, returnType, resultErrorName, receiverType, model, diagnostics);
|
||||
analyzeAssignmentStatement(assignStatement, context);
|
||||
}
|
||||
}
|
||||
|
||||
private void analyzeReturnStatement(
|
||||
final PbsAst.Expression value,
|
||||
final Scope scope,
|
||||
final TypeView returnType,
|
||||
final String resultErrorName,
|
||||
final TypeView receiverType,
|
||||
final Model model,
|
||||
final DiagnosticSink diagnostics) {
|
||||
final PbsFlowBodyContext context) {
|
||||
final var root = unwrapGroup(value);
|
||||
if (root instanceof PbsAst.OkExpr okExpr) {
|
||||
analyzeReturnOk(okExpr, scope, returnType, resultErrorName, receiverType, model, diagnostics);
|
||||
analyzeReturnOk(okExpr, context);
|
||||
return;
|
||||
}
|
||||
if (root instanceof PbsAst.ErrExpr errExpr) {
|
||||
analyzeReturnErr(errExpr, returnType, resultErrorName, model, diagnostics);
|
||||
analyzeReturnErr(errExpr, context);
|
||||
return;
|
||||
}
|
||||
expressionAnalyzer.analyzeExpression(
|
||||
value,
|
||||
scope,
|
||||
returnType,
|
||||
returnType,
|
||||
resultErrorName,
|
||||
receiverType,
|
||||
model,
|
||||
diagnostics,
|
||||
context.scope(),
|
||||
context.returnType(),
|
||||
context.returnType(),
|
||||
context.resultErrorName(),
|
||||
context.receiverType(),
|
||||
context.model(),
|
||||
context.diagnostics(),
|
||||
ExprUse.VALUE,
|
||||
true,
|
||||
this::analyzeBlock);
|
||||
@ -510,12 +547,10 @@ final class PbsFlowBodyAnalyzer {
|
||||
|
||||
private void analyzeReturnOk(
|
||||
final PbsAst.OkExpr okExpr,
|
||||
final Scope scope,
|
||||
final TypeView returnType,
|
||||
final String resultErrorName,
|
||||
final TypeView receiverType,
|
||||
final Model model,
|
||||
final DiagnosticSink diagnostics) {
|
||||
final PbsFlowBodyContext context) {
|
||||
final var returnType = context.returnType();
|
||||
final var resultErrorName = context.resultErrorName();
|
||||
final var diagnostics = context.diagnostics();
|
||||
if (returnType.kind() != Kind.RESULT || resultErrorName == null) {
|
||||
Diagnostics.error(diagnostics,
|
||||
PbsSemanticsErrors.E_SEM_RESULT_FLOW_INVALID_POSITION.name(),
|
||||
@ -523,12 +558,12 @@ final class PbsFlowBodyAnalyzer {
|
||||
okExpr.span());
|
||||
expressionAnalyzer.analyzeExpression(
|
||||
okExpr.value(),
|
||||
scope,
|
||||
context.scope(),
|
||||
null,
|
||||
returnType,
|
||||
resultErrorName,
|
||||
receiverType,
|
||||
model,
|
||||
context.receiverType(),
|
||||
context.model(),
|
||||
diagnostics,
|
||||
ExprUse.VALUE,
|
||||
true,
|
||||
@ -539,12 +574,12 @@ final class PbsFlowBodyAnalyzer {
|
||||
final var payloadType = returnType.inner();
|
||||
final var actualType = expressionAnalyzer.analyzeExpression(
|
||||
okExpr.value(),
|
||||
scope,
|
||||
context.scope(),
|
||||
payloadType,
|
||||
returnType,
|
||||
resultErrorName,
|
||||
receiverType,
|
||||
model,
|
||||
context.receiverType(),
|
||||
context.model(),
|
||||
diagnostics,
|
||||
ExprUse.VALUE,
|
||||
true,
|
||||
@ -559,10 +594,11 @@ final class PbsFlowBodyAnalyzer {
|
||||
|
||||
private void analyzeReturnErr(
|
||||
final PbsAst.ErrExpr errExpr,
|
||||
final TypeView returnType,
|
||||
final String resultErrorName,
|
||||
final Model model,
|
||||
final DiagnosticSink diagnostics) {
|
||||
final PbsFlowBodyContext context) {
|
||||
final var returnType = context.returnType();
|
||||
final var resultErrorName = context.resultErrorName();
|
||||
final var model = context.model();
|
||||
final var diagnostics = context.diagnostics();
|
||||
if (returnType.kind() != Kind.RESULT || resultErrorName == null) {
|
||||
Diagnostics.error(diagnostics,
|
||||
PbsSemanticsErrors.E_SEM_RESULT_FLOW_INVALID_POSITION.name(),
|
||||
@ -601,13 +637,14 @@ final class PbsFlowBodyAnalyzer {
|
||||
|
||||
private void analyzeAssignmentStatement(
|
||||
final PbsAst.AssignStatement assignStatement,
|
||||
final Scope scope,
|
||||
final TypeView returnType,
|
||||
final String resultErrorName,
|
||||
final TypeView receiverType,
|
||||
final Model model,
|
||||
final DiagnosticSink diagnostics) {
|
||||
final var target = resolveAssignmentTarget(assignStatement.target(), scope, receiverType, model, diagnostics);
|
||||
final PbsFlowBodyContext context) {
|
||||
final var scope = context.scope();
|
||||
final var returnType = context.returnType();
|
||||
final var resultErrorName = context.resultErrorName();
|
||||
final var receiverType = context.receiverType();
|
||||
final var model = context.model();
|
||||
final var diagnostics = context.diagnostics();
|
||||
final var target = resolveAssignmentTarget(assignStatement.target(), context);
|
||||
final var expectedType = target.type();
|
||||
final var valueType = expressionAnalyzer.analyzeExpression(
|
||||
assignStatement.value(),
|
||||
@ -636,10 +673,11 @@ final class PbsFlowBodyAnalyzer {
|
||||
|
||||
private AssignmentTargetResolution resolveAssignmentTarget(
|
||||
final PbsAst.LValue lValue,
|
||||
final Scope scope,
|
||||
final TypeView receiverType,
|
||||
final Model model,
|
||||
final DiagnosticSink diagnostics) {
|
||||
final PbsFlowBodyContext context) {
|
||||
final var scope = context.scope();
|
||||
final var receiverType = context.receiverType();
|
||||
final var model = context.model();
|
||||
final var diagnostics = context.diagnostics();
|
||||
final var rootName = lValue.rootName();
|
||||
final var rootIsThis = "this".equals(rootName);
|
||||
if (lValue.pathSegments().isEmpty()) {
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
package p.studio.compiler.pbs.semantics;
|
||||
|
||||
import p.studio.compiler.source.diagnostics.DiagnosticSink;
|
||||
import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.Model;
|
||||
import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.Scope;
|
||||
import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.TypeView;
|
||||
|
||||
final class PbsFlowBodyContext {
|
||||
private final Scope scope;
|
||||
private final TypeView returnType;
|
||||
private final String resultErrorName;
|
||||
private final TypeView receiverType;
|
||||
private final Model model;
|
||||
private final DiagnosticSink diagnostics;
|
||||
|
||||
PbsFlowBodyContext(
|
||||
final Scope scope,
|
||||
final TypeView returnType,
|
||||
final String resultErrorName,
|
||||
final TypeView receiverType,
|
||||
final Model model,
|
||||
final DiagnosticSink diagnostics) {
|
||||
this.scope = scope;
|
||||
this.returnType = returnType;
|
||||
this.resultErrorName = resultErrorName;
|
||||
this.receiverType = receiverType;
|
||||
this.model = model;
|
||||
this.diagnostics = diagnostics;
|
||||
}
|
||||
|
||||
Scope scope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
TypeView returnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
String resultErrorName() {
|
||||
return resultErrorName;
|
||||
}
|
||||
|
||||
TypeView receiverType() {
|
||||
return receiverType;
|
||||
}
|
||||
|
||||
Model model() {
|
||||
return model;
|
||||
}
|
||||
|
||||
DiagnosticSink diagnostics() {
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
PbsFlowBodyContext withScope(final Scope nextScope) {
|
||||
return new PbsFlowBodyContext(
|
||||
nextScope,
|
||||
returnType,
|
||||
resultErrorName,
|
||||
receiverType,
|
||||
model,
|
||||
diagnostics);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user