implements PR-13.1

This commit is contained in:
bQUARKz 2026-03-10 10:26:08 +00:00
parent df0d9f4601
commit f8f520d284
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
2 changed files with 201 additions and 99 deletions

View File

@ -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()) {

View File

@ -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);
}
}