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