implements PR-12.1

This commit is contained in:
bQUARKz 2026-03-10 10:13:17 +00:00
parent 852ff351ed
commit 8edd2c4b4b
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
2 changed files with 248 additions and 428 deletions

View File

@ -32,7 +32,6 @@ final class PbsFlowExpressionAnalyzer {
} }
private final PbsFlowTypeOps typeOps; private final PbsFlowTypeOps typeOps;
private BlockAnalyzer blockAnalyzer;
PbsFlowExpressionAnalyzer(final PbsFlowTypeOps typeOps) { PbsFlowExpressionAnalyzer(final PbsFlowTypeOps typeOps) {
this.typeOps = typeOps; this.typeOps = typeOps;
@ -50,35 +49,33 @@ final class PbsFlowExpressionAnalyzer {
final ExprUse use, final ExprUse use,
final boolean valueContext, final boolean valueContext,
final BlockAnalyzer blockAnalyzer) { final BlockAnalyzer blockAnalyzer) {
final var previousBlockAnalyzer = this.blockAnalyzer; return analyzeExpressionInternal(
this.blockAnalyzer = blockAnalyzer; expression,
try { new PbsFlowExpressionContext(
return analyzeExpressionInternal( scope,
expression, expectedType,
scope, returnType,
expectedType, resultErrorName,
returnType, receiverType,
resultErrorName, model,
receiverType, diagnostics,
model, use,
diagnostics, valueContext,
use, blockAnalyzer));
valueContext);
} finally {
this.blockAnalyzer = previousBlockAnalyzer;
}
} }
private ExprResult analyzeExpressionInternal( private ExprResult analyzeExpressionInternal(
final PbsAst.Expression expression, final PbsAst.Expression expression,
final Scope scope, final PbsFlowExpressionContext context) {
final TypeView expectedType, final var scope = context.scope();
final TypeView returnType, final var expectedType = context.expectedType();
final String resultErrorName, final var returnType = context.returnType();
final TypeView receiverType, final var resultErrorName = context.resultErrorName();
final Model model, final var receiverType = context.receiverType();
final DiagnosticSink diagnostics, final var model = context.model();
final ExprUse use, final var diagnostics = context.diagnostics();
final boolean valueContext) { final var use = context.use();
final var valueContext = context.valueContext();
if (expression instanceof PbsAst.IntLiteralExpr) { if (expression instanceof PbsAst.IntLiteralExpr) {
return ExprResult.type(TypeView.intType()); return ExprResult.type(TypeView.intType());
} }
@ -140,59 +137,21 @@ final class PbsFlowExpressionAnalyzer {
return ExprResult.type(TypeView.unknown()); return ExprResult.type(TypeView.unknown());
} }
if (expression instanceof PbsAst.GroupExpr groupExpr) { if (expression instanceof PbsAst.GroupExpr groupExpr) {
return analyzeExpressionInternal( return analyzeExpressionInternal(groupExpr.expression(), context);
groupExpr.expression(),
scope,
expectedType,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
use,
valueContext);
} }
if (expression instanceof PbsAst.TupleExpr tupleExpr) { if (expression instanceof PbsAst.TupleExpr tupleExpr) {
final var fields = new ArrayList<TupleField>(tupleExpr.items().size()); final var fields = new ArrayList<TupleField>(tupleExpr.items().size());
for (final var item : tupleExpr.items()) { for (final var item : tupleExpr.items()) {
final var value = analyzeExpressionInternal( final var value = analyzeValueExpression(item.expression(), context, null).type();
item.expression(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
fields.add(new TupleField(item.label(), value)); fields.add(new TupleField(item.label(), value));
} }
return ExprResult.type(TypeView.tuple(fields)); return ExprResult.type(TypeView.tuple(fields));
} }
if (expression instanceof PbsAst.BlockExpr blockExpr) { if (expression instanceof PbsAst.BlockExpr blockExpr) {
return ExprResult.type(blockAnalyzer.analyze( return ExprResult.type(analyzeBlock(blockExpr.block(), context, valueContext));
blockExpr.block(),
scope,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
valueContext));
} }
if (expression instanceof PbsAst.UnaryExpr unaryExpr) { if (expression instanceof PbsAst.UnaryExpr unaryExpr) {
final var operand = analyzeExpressionInternal( final var operand = analyzeValueExpression(unaryExpr.expression(), context, null).type();
unaryExpr.expression(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
if ("!".equals(unaryExpr.operator()) || "not".equals(unaryExpr.operator())) { if ("!".equals(unaryExpr.operator()) || "not".equals(unaryExpr.operator())) {
return ExprResult.type(TypeView.bool()); return ExprResult.type(TypeView.bool());
} }
@ -202,75 +161,23 @@ final class PbsFlowExpressionAnalyzer {
return ExprResult.type(TypeView.unknown()); return ExprResult.type(TypeView.unknown());
} }
if (expression instanceof PbsAst.BinaryExpr binaryExpr) { if (expression instanceof PbsAst.BinaryExpr binaryExpr) {
final var left = analyzeExpressionInternal( final var left = analyzeValueExpression(binaryExpr.left(), context, null).type();
binaryExpr.left(), final var right = analyzeValueExpression(binaryExpr.right(), context, null).type();
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
final var right = analyzeExpressionInternal(
binaryExpr.right(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
return ExprResult.type(typeOps.inferBinaryResult(binaryExpr.operator(), left, right)); return ExprResult.type(typeOps.inferBinaryResult(binaryExpr.operator(), left, right));
} }
if (expression instanceof PbsAst.MemberExpr memberExpr) { if (expression instanceof PbsAst.MemberExpr memberExpr) {
return analyzeMemberExpression( return analyzeMemberExpression(
memberExpr, memberExpr,
scope, context);
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
use);
} }
if (expression instanceof PbsAst.CallExpr callExpr) { if (expression instanceof PbsAst.CallExpr callExpr) {
return analyzeCallExpression( return analyzeCallExpression(callExpr, context);
callExpr,
scope,
expectedType,
returnType,
resultErrorName,
receiverType,
model,
diagnostics);
} }
if (expression instanceof PbsAst.ApplyExpr applyExpr) { if (expression instanceof PbsAst.ApplyExpr applyExpr) {
return analyzeApplyExpression( return analyzeApplyExpression(applyExpr, context);
applyExpr,
scope,
expectedType,
returnType,
resultErrorName,
receiverType,
model,
diagnostics);
} }
if (expression instanceof PbsAst.IfExpr ifExpr) { if (expression instanceof PbsAst.IfExpr ifExpr) {
final var condition = analyzeExpressionInternal( final var condition = analyzeValueExpression(ifExpr.condition(), context, TypeView.bool()).type();
ifExpr.condition(),
scope,
TypeView.bool(),
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
if (!typeOps.isBool(condition)) { if (!typeOps.isBool(condition)) {
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
PbsSemanticsErrors.E_SEM_IF_NON_BOOL_CONDITION.name(), PbsSemanticsErrors.E_SEM_IF_NON_BOOL_CONDITION.name(),
@ -278,18 +185,8 @@ final class PbsFlowExpressionAnalyzer {
ifExpr.condition().span()); ifExpr.condition().span());
} }
final var thenType = blockAnalyzer.analyze(ifExpr.thenBlock(), scope, returnType, resultErrorName, receiverType, model, diagnostics, true); final var thenType = analyzeBlock(ifExpr.thenBlock(), context, true);
final var elseType = analyzeExpressionInternal( final var elseType = analyzeValueExpression(ifExpr.elseExpression(), context, expectedType).type();
ifExpr.elseExpression(),
scope,
expectedType,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
if (!typeOps.compatible(thenType, elseType)) { if (!typeOps.compatible(thenType, elseType)) {
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
@ -301,60 +198,21 @@ final class PbsFlowExpressionAnalyzer {
return ExprResult.type(thenType); return ExprResult.type(thenType);
} }
if (expression instanceof PbsAst.SwitchExpr switchExpr) { if (expression instanceof PbsAst.SwitchExpr switchExpr) {
return ExprResult.type(analyzeSwitchExpression( return ExprResult.type(analyzeSwitchExpression(switchExpr, context));
switchExpr,
scope,
expectedType,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
valueContext));
} }
if (expression instanceof PbsAst.ElseExpr elseExpr) { if (expression instanceof PbsAst.ElseExpr elseExpr) {
final var optional = analyzeExpressionInternal( final var optional = analyzeValueExpression(elseExpr.optionalExpression(), context, null).type();
elseExpr.optionalExpression(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
if (optional.kind() != Kind.OPTIONAL) { if (optional.kind() != Kind.OPTIONAL) {
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
PbsSemanticsErrors.E_SEM_ELSE_NON_OPTIONAL_LEFT.name(), PbsSemanticsErrors.E_SEM_ELSE_NON_OPTIONAL_LEFT.name(),
"Left operand of 'else' must have optional type", "Left operand of 'else' must have optional type",
elseExpr.optionalExpression().span()); elseExpr.optionalExpression().span());
analyzeExpressionInternal( analyzeValueExpression(elseExpr.fallbackExpression(), context, null);
elseExpr.fallbackExpression(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true);
return ExprResult.type(TypeView.unknown()); return ExprResult.type(TypeView.unknown());
} }
final var payload = optional.inner(); final var payload = optional.inner();
final var fallback = analyzeExpressionInternal( final var fallback = analyzeValueExpression(elseExpr.fallbackExpression(), context, payload).type();
elseExpr.fallbackExpression(),
scope,
payload,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
if (!typeOps.compatible(fallback, payload)) { if (!typeOps.compatible(fallback, payload)) {
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
PbsSemanticsErrors.E_SEM_ELSE_FALLBACK_TYPE_MISMATCH.name(), PbsSemanticsErrors.E_SEM_ELSE_FALLBACK_TYPE_MISMATCH.name(),
@ -364,17 +222,7 @@ final class PbsFlowExpressionAnalyzer {
return ExprResult.type(payload); return ExprResult.type(payload);
} }
if (expression instanceof PbsAst.PropagateExpr propagateExpr) { if (expression instanceof PbsAst.PropagateExpr propagateExpr) {
final var source = analyzeExpressionInternal( final var source = analyzeValueExpression(propagateExpr.expression(), context, null).type();
propagateExpr.expression(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
if (source.kind() != Kind.RESULT) { if (source.kind() != Kind.RESULT) {
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
PbsSemanticsErrors.E_SEM_RESULT_PROPAGATE_NON_RESULT.name(), PbsSemanticsErrors.E_SEM_RESULT_PROPAGATE_NON_RESULT.name(),
@ -392,14 +240,7 @@ final class PbsFlowExpressionAnalyzer {
return ExprResult.type(source.inner()); return ExprResult.type(source.inner());
} }
if (expression instanceof PbsAst.HandleExpr handleExpr) { if (expression instanceof PbsAst.HandleExpr handleExpr) {
return ExprResult.type(analyzeHandleExpression( return ExprResult.type(analyzeHandleExpression(handleExpr, context));
handleExpr,
scope,
returnType,
resultErrorName,
receiverType,
model,
diagnostics));
} }
if (expression instanceof PbsAst.NoneExpr noneExpr) { if (expression instanceof PbsAst.NoneExpr noneExpr) {
if (expectedType == null || expectedType.kind() != Kind.OPTIONAL) { if (expectedType == null || expectedType.kind() != Kind.OPTIONAL) {
@ -415,31 +256,11 @@ final class PbsFlowExpressionAnalyzer {
final var payloadExpected = expectedType != null && expectedType.kind() == Kind.OPTIONAL final var payloadExpected = expectedType != null && expectedType.kind() == Kind.OPTIONAL
? expectedType.inner() ? expectedType.inner()
: null; : null;
final var payload = analyzeExpressionInternal( final var payload = analyzeValueExpression(someExpr.value(), context, payloadExpected).type();
someExpr.value(),
scope,
payloadExpected,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
return ExprResult.type(TypeView.optional(payloadExpected == null ? payload : payloadExpected)); return ExprResult.type(TypeView.optional(payloadExpected == null ? payload : payloadExpected));
} }
if (expression instanceof PbsAst.BindExpr bindExpr) { if (expression instanceof PbsAst.BindExpr bindExpr) {
final var contextType = analyzeExpressionInternal( final var contextType = analyzeValueExpression(bindExpr.contextExpression(), context, null).type();
bindExpr.contextExpression(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
if (expectedType == null || expectedType.kind() != Kind.CALLBACK) { if (expectedType == null || expectedType.kind() != Kind.CALLBACK) {
return ExprResult.type(TypeView.unknown()); return ExprResult.type(TypeView.unknown());
} }
@ -491,17 +312,7 @@ final class PbsFlowExpressionAnalyzer {
return ExprResult.type(TypeView.unknown()); return ExprResult.type(TypeView.unknown());
} }
if (expression instanceof PbsAst.AsExpr asExpr) { if (expression instanceof PbsAst.AsExpr asExpr) {
analyzeExpressionInternal( analyzeValueExpression(asExpr.expression(), context, null);
asExpr.expression(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true);
if (model.contracts.containsKey(asExpr.contractName())) { if (model.contracts.containsKey(asExpr.contractName())) {
return ExprResult.type(TypeView.contract(asExpr.contractName())); return ExprResult.type(TypeView.contract(asExpr.contractName()));
} }
@ -513,17 +324,7 @@ final class PbsFlowExpressionAnalyzer {
PbsSemanticsErrors.E_SEM_RESULT_FLOW_INVALID_POSITION.name(), PbsSemanticsErrors.E_SEM_RESULT_FLOW_INVALID_POSITION.name(),
"'ok(...)' is only allowed in result return flow and handle arm terminals", "'ok(...)' is only allowed in result return flow and handle arm terminals",
okExpr.span()); okExpr.span());
analyzeExpressionInternal( analyzeValueExpression(okExpr.value(), context, null);
okExpr.value(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true);
return ExprResult.type(TypeView.unknown()); return ExprResult.type(TypeView.unknown());
} }
if (expression instanceof PbsAst.ErrExpr errExpr) { if (expression instanceof PbsAst.ErrExpr errExpr) {
@ -539,54 +340,18 @@ final class PbsFlowExpressionAnalyzer {
private ExprResult analyzeCallExpression( private ExprResult analyzeCallExpression(
final PbsAst.CallExpr callExpr, final PbsAst.CallExpr callExpr,
final Scope scope, final PbsFlowExpressionContext context) {
final TypeView expectedType, final var callee = analyzeTargetExpression(callExpr.callee(), context, ExprUse.CALL_TARGET);
final TypeView returnType,
final String resultErrorName,
final TypeView receiverType,
final Model model,
final DiagnosticSink diagnostics) {
final var callee = analyzeExpressionInternal(
callExpr.callee(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.CALL_TARGET,
true);
final TypeView argumentType; final TypeView argumentType;
if (callExpr.arguments().isEmpty()) { if (callExpr.arguments().isEmpty()) {
argumentType = TypeView.unit(); argumentType = TypeView.unit();
} else if (callExpr.arguments().size() == 1) { } else if (callExpr.arguments().size() == 1) {
argumentType = analyzeExpressionInternal( argumentType = analyzeValueExpression(callExpr.arguments().getFirst(), context, null).type();
callExpr.arguments().getFirst(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
} else { } else {
final var fields = new ArrayList<TupleField>(callExpr.arguments().size()); final var fields = new ArrayList<TupleField>(callExpr.arguments().size());
for (final var argument : callExpr.arguments()) { for (final var argument : callExpr.arguments()) {
final var itemType = analyzeExpressionInternal( final var itemType = analyzeValueExpression(argument, context, null).type();
argument,
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
fields.add(new TupleField(null, itemType)); fields.add(new TupleField(null, itemType));
} }
argumentType = TypeView.tuple(fields); argumentType = TypeView.tuple(fields);
@ -597,49 +362,23 @@ final class PbsFlowExpressionAnalyzer {
callExpr.callee().span(), callExpr.callee().span(),
callee, callee,
argumentType, argumentType,
expectedType, context.expectedType(),
diagnostics); context.diagnostics());
} }
private ExprResult analyzeApplyExpression( private ExprResult analyzeApplyExpression(
final PbsAst.ApplyExpr applyExpr, final PbsAst.ApplyExpr applyExpr,
final Scope scope, final PbsFlowExpressionContext context) {
final TypeView expectedType, final var callee = analyzeTargetExpression(applyExpr.callee(), context, ExprUse.APPLY_TARGET);
final TypeView returnType, final var argument = analyzeValueExpression(applyExpr.argument(), context, null).type();
final String resultErrorName,
final TypeView receiverType,
final Model model,
final DiagnosticSink diagnostics) {
final var callee = analyzeExpressionInternal(
applyExpr.callee(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.APPLY_TARGET,
true);
final var argument = analyzeExpressionInternal(
applyExpr.argument(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
return resolveCallableApplication( return resolveCallableApplication(
applyExpr.span(), applyExpr.span(),
applyExpr.callee().span(), applyExpr.callee().span(),
callee, callee,
argument, argument,
expectedType, context.expectedType(),
diagnostics); context.diagnostics());
} }
private ExprResult resolveCallableApplication( private ExprResult resolveCallableApplication(
@ -702,24 +441,12 @@ final class PbsFlowExpressionAnalyzer {
private ExprResult analyzeMemberExpression( private ExprResult analyzeMemberExpression(
final PbsAst.MemberExpr memberExpr, final PbsAst.MemberExpr memberExpr,
final Scope scope, final PbsFlowExpressionContext context) {
final TypeView returnType, final var receiver = analyzeValueExpression(memberExpr.receiver(), context, null).type();
final String resultErrorName, final var model = context.model();
final TypeView receiverType, final var diagnostics = context.diagnostics();
final Model model, final var receiverType = context.receiverType();
final DiagnosticSink diagnostics, final var use = context.use();
final ExprUse use) {
final var receiver = analyzeExpressionInternal(
memberExpr.receiver(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
if (receiver.kind() == Kind.TYPE_REF) { if (receiver.kind() == Kind.TYPE_REF) {
final var enumCases = model.enums.get(receiver.name()); final var enumCases = model.enums.get(receiver.name());
@ -857,25 +584,10 @@ final class PbsFlowExpressionAnalyzer {
private TypeView analyzeSwitchExpression( private TypeView analyzeSwitchExpression(
final PbsAst.SwitchExpr switchExpr, final PbsAst.SwitchExpr switchExpr,
final Scope scope, final PbsFlowExpressionContext context) {
final TypeView expectedType, final var model = context.model();
final TypeView returnType, final var diagnostics = context.diagnostics();
final String resultErrorName, final var selector = analyzeValueExpression(switchExpr.selector(), context, null).type();
final TypeView receiverType,
final Model model,
final DiagnosticSink diagnostics,
final boolean valueContext) {
final var selector = analyzeExpressionInternal(
switchExpr.selector(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
final var selectorComparable = typeOps.isScalarComparable(selector) || selector.kind() == Kind.ENUM; final var selectorComparable = typeOps.isScalarComparable(selector) || selector.kind() == Kind.ENUM;
if (!selectorComparable) { if (!selectorComparable) {
@ -928,15 +640,7 @@ final class PbsFlowExpressionAnalyzer {
arm.pattern().span()); arm.pattern().span());
} }
final var currentArmType = blockAnalyzer.analyze( final var currentArmType = analyzeBlock(arm.block(), context, true);
arm.block(),
scope,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
true);
if (armType == null) { if (armType == null) {
armType = currentArmType; armType = currentArmType;
} else if (!typeOps.compatible(currentArmType, armType)) { } else if (!typeOps.compatible(currentArmType, armType)) {
@ -947,7 +651,7 @@ final class PbsFlowExpressionAnalyzer {
} }
} }
if (valueContext && !hasWildcard) { if (context.valueContext() && !hasWildcard) {
var exhaustive = false; var exhaustive = false;
if (selector.kind() == Kind.ENUM) { if (selector.kind() == Kind.ENUM) {
final var allCases = model.enums.get(selector.name()); final var allCases = model.enums.get(selector.name());
@ -974,8 +678,8 @@ final class PbsFlowExpressionAnalyzer {
if (armType == null) { if (armType == null) {
return TypeView.unit(); return TypeView.unit();
} }
if (expectedType != null && typeOps.compatible(armType, expectedType)) { if (context.expectedType() != null && typeOps.compatible(armType, context.expectedType())) {
return expectedType; return context.expectedType();
} }
return armType; return armType;
} }
@ -1037,23 +741,11 @@ final class PbsFlowExpressionAnalyzer {
private TypeView analyzeHandleExpression( private TypeView analyzeHandleExpression(
final PbsAst.HandleExpr handleExpr, final PbsAst.HandleExpr handleExpr,
final Scope scope, final PbsFlowExpressionContext context) {
final TypeView returnType, final var model = context.model();
final String resultErrorName, final var diagnostics = context.diagnostics();
final TypeView receiverType, final var resultErrorName = context.resultErrorName();
final Model model, final var sourceType = analyzeValueExpression(handleExpr.value(), context, null).type();
final DiagnosticSink diagnostics) {
final var sourceType = analyzeExpressionInternal(
handleExpr.value(),
scope,
null,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
ExprUse.VALUE,
true).type();
if (sourceType.kind() != Kind.RESULT) { if (sourceType.kind() != Kind.RESULT) {
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
PbsSemanticsErrors.E_SEM_HANDLE_NON_RESULT.name(), PbsSemanticsErrors.E_SEM_HANDLE_NON_RESULT.name(),
@ -1107,11 +799,8 @@ final class PbsFlowExpressionAnalyzer {
} }
analyzeHandleBlockArm( analyzeHandleBlockArm(
arm, arm,
scope, context,
sourcePayloadType, sourcePayloadType,
returnType,
resultErrorName,
receiverType,
model, model,
diagnostics); diagnostics);
} }
@ -1128,13 +817,14 @@ final class PbsFlowExpressionAnalyzer {
private void analyzeHandleBlockArm( private void analyzeHandleBlockArm(
final PbsAst.HandleArm arm, final PbsAst.HandleArm arm,
final Scope scope, final PbsFlowExpressionContext context,
final TypeView sourcePayloadType, final TypeView sourcePayloadType,
final TypeView returnType,
final String resultErrorName,
final TypeView receiverType,
final Model model, final Model model,
final DiagnosticSink diagnostics) { final DiagnosticSink diagnostics) {
final var returnType = context.returnType();
final var resultErrorName = context.resultErrorName();
final var receiverType = context.receiverType();
final var scope = context.scope();
if (arm.block() == null) { if (arm.block() == null) {
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
PbsSemanticsErrors.E_SEM_HANDLE_ARM_TERMINAL_INVALID.name(), PbsSemanticsErrors.E_SEM_HANDLE_ARM_TERMINAL_INVALID.name(),
@ -1147,15 +837,7 @@ final class PbsFlowExpressionAnalyzer {
final var terminal = unwrapGroup(block.tailExpression()); final var terminal = unwrapGroup(block.tailExpression());
if (terminal instanceof PbsAst.OkExpr okExpr) { if (terminal instanceof PbsAst.OkExpr okExpr) {
final var payloadBlock = new PbsAst.Block(block.statements(), okExpr.value(), block.span()); final var payloadBlock = new PbsAst.Block(block.statements(), okExpr.value(), block.span());
final var actualPayloadType = blockAnalyzer.analyze( final var actualPayloadType = analyzeBlock(payloadBlock, context, true);
payloadBlock,
scope,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
true);
if (!typeOps.compatible(actualPayloadType, sourcePayloadType)) { if (!typeOps.compatible(actualPayloadType, sourcePayloadType)) {
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
PbsSemanticsErrors.E_SEM_RESULT_OK_PAYLOAD_MISMATCH.name(), PbsSemanticsErrors.E_SEM_RESULT_OK_PAYLOAD_MISMATCH.name(),
@ -1167,15 +849,7 @@ final class PbsFlowExpressionAnalyzer {
if (terminal instanceof PbsAst.ErrExpr errExpr) { if (terminal instanceof PbsAst.ErrExpr errExpr) {
final var statementsOnly = new PbsAst.Block(block.statements(), null, block.span()); final var statementsOnly = new PbsAst.Block(block.statements(), null, block.span());
blockAnalyzer.analyze( analyzeBlock(statementsOnly, context, false);
statementsOnly,
scope,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
false);
if (resultErrorName != null && !matchesTargetError(errExpr.errorPath(), resultErrorName, model)) { if (resultErrorName != null && !matchesTargetError(errExpr.errorPath(), resultErrorName, model)) {
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
PbsSemanticsErrors.E_SEM_RESULT_ERROR_LABEL_INVALID.name(), PbsSemanticsErrors.E_SEM_RESULT_ERROR_LABEL_INVALID.name(),
@ -1187,25 +861,9 @@ final class PbsFlowExpressionAnalyzer {
if (block.tailExpression() == null) { if (block.tailExpression() == null) {
final var statementsOnly = new PbsAst.Block(block.statements(), null, block.span()); final var statementsOnly = new PbsAst.Block(block.statements(), null, block.span());
blockAnalyzer.analyze( analyzeBlock(statementsOnly, context, false);
statementsOnly,
scope,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
false);
} else { } else {
blockAnalyzer.analyze( analyzeBlock(block, context, true);
block,
scope,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
true);
} }
p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics, p.studio.compiler.source.diagnostics.Diagnostics.error(diagnostics,
PbsSemanticsErrors.E_SEM_HANDLE_ARM_TERMINAL_INVALID.name(), PbsSemanticsErrors.E_SEM_HANDLE_ARM_TERMINAL_INVALID.name(),
@ -1236,4 +894,41 @@ final class PbsFlowExpressionAnalyzer {
return expression; return expression;
} }
private ExprResult analyzeValueExpression(
final PbsAst.Expression expression,
final PbsFlowExpressionContext context,
final TypeView expectedType) {
return analyzeExpressionInternal(
expression,
context.withExpectedType(expectedType)
.withUse(ExprUse.VALUE)
.withValueContext(true));
}
private ExprResult analyzeTargetExpression(
final PbsAst.Expression expression,
final PbsFlowExpressionContext context,
final ExprUse use) {
return analyzeExpressionInternal(
expression,
context.withExpectedType(null)
.withUse(use)
.withValueContext(true));
}
private TypeView analyzeBlock(
final PbsAst.Block block,
final PbsFlowExpressionContext context,
final boolean valueContext) {
return context.blockAnalyzer().analyze(
block,
context.scope(),
context.returnType(),
context.resultErrorName(),
context.receiverType(),
context.model(),
context.diagnostics(),
valueContext);
}
} }

View File

@ -0,0 +1,125 @@
package p.studio.compiler.pbs.semantics;
import p.studio.compiler.source.diagnostics.DiagnosticSink;
import p.studio.compiler.pbs.semantics.PbsFlowSemanticSupport.ExprUse;
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 PbsFlowExpressionContext {
private final Scope scope;
private final TypeView expectedType;
private final TypeView returnType;
private final String resultErrorName;
private final TypeView receiverType;
private final Model model;
private final DiagnosticSink diagnostics;
private final ExprUse use;
private final boolean valueContext;
private final PbsFlowExpressionAnalyzer.BlockAnalyzer blockAnalyzer;
PbsFlowExpressionContext(
final Scope scope,
final TypeView expectedType,
final TypeView returnType,
final String resultErrorName,
final TypeView receiverType,
final Model model,
final DiagnosticSink diagnostics,
final ExprUse use,
final boolean valueContext,
final PbsFlowExpressionAnalyzer.BlockAnalyzer blockAnalyzer) {
this.scope = scope;
this.expectedType = expectedType;
this.returnType = returnType;
this.resultErrorName = resultErrorName;
this.receiverType = receiverType;
this.model = model;
this.diagnostics = diagnostics;
this.use = use;
this.valueContext = valueContext;
this.blockAnalyzer = blockAnalyzer;
}
Scope scope() {
return scope;
}
TypeView expectedType() {
return expectedType;
}
TypeView returnType() {
return returnType;
}
String resultErrorName() {
return resultErrorName;
}
TypeView receiverType() {
return receiverType;
}
Model model() {
return model;
}
DiagnosticSink diagnostics() {
return diagnostics;
}
ExprUse use() {
return use;
}
boolean valueContext() {
return valueContext;
}
PbsFlowExpressionAnalyzer.BlockAnalyzer blockAnalyzer() {
return blockAnalyzer;
}
PbsFlowExpressionContext withExpectedType(final TypeView nextExpectedType) {
return new PbsFlowExpressionContext(
scope,
nextExpectedType,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
use,
valueContext,
blockAnalyzer);
}
PbsFlowExpressionContext withUse(final ExprUse nextUse) {
return new PbsFlowExpressionContext(
scope,
expectedType,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
nextUse,
valueContext,
blockAnalyzer);
}
PbsFlowExpressionContext withValueContext(final boolean nextValueContext) {
return new PbsFlowExpressionContext(
scope,
expectedType,
returnType,
resultErrorName,
receiverType,
model,
diagnostics,
use,
nextValueContext,
blockAnalyzer);
}
}