From 2e008d29e5d956f5463fa27c397f395a7e106d9e Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sun, 2 Jul 2023 13:13:58 +0100 Subject: Check call effect is sub-effect of function effect --- .../java/org/shedlang/compiler/ShedCompiler.java | 2 +- .../shedlang/compiler/typechecker/TypeChecker.java | 16 +++++++++++-- .../compiler/typechecker/TypeCheckerContext.java | 26 ++++++++++++++++++---- .../typechecker/errors/UnexpectedEffectError.java | 24 ++++++++++++++++++++ 4 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/shedlang/compiler/typechecker/errors/UnexpectedEffectError.java (limited to 'src/main/java') diff --git a/src/main/java/org/shedlang/compiler/ShedCompiler.java b/src/main/java/org/shedlang/compiler/ShedCompiler.java index d727aea5..8f63ce75 100644 --- a/src/main/java/org/shedlang/compiler/ShedCompiler.java +++ b/src/main/java/org/shedlang/compiler/ShedCompiler.java @@ -46,7 +46,7 @@ public class ShedCompiler { Types.UNIT )) )) - .enter(P.map( + .enterBlock(P.map( Map.entry("Io", Types.effectType(Effects.IO)), Map.entry("Unit", Types.metaType(Types.UNIT)), diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java index 591d4810..3b128801 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java @@ -28,6 +28,10 @@ public class TypeChecker { } } + private static boolean isSubEffect(Effect subEffect, Effect superEffect, TypeCheckerContext context) { + return subEffect.equals(superEffect); + } + private static boolean isSubType(Type subType, Type superType, TypeCheckerContext context) { return subType.equals(superType); } @@ -152,10 +156,18 @@ public class TypeChecker { throw new FunctionHasNoEffectsError(untyped.source()); } + if (!isSubEffect(receiverType.effect(), context.effect(), context)) { + throw new UnexpectedEffectError( + context.effect(), + receiverType.effect(), + untyped.source() + ); + } + return context.toResult(new TypedCallNode( typedReceiver, typedArgs, - false, + untyped.hasEffects(), receiverType.returnType(), untyped.source() )); @@ -220,7 +232,7 @@ public class TypeChecker { var bodyEnvironment = typedParams.all() .map(param -> Map.entry(param.name(), param.type().value())) .collect(PCollectors.toMap()); - var bodyContext = context.enter(bodyEnvironment); + var bodyContext = context.enterFunction(bodyEnvironment, typedEffect.map(e -> e.value()).orElse(Effects.NONE)); var bodyResult = bodyContext.mapWithContext( untyped.body(), diff --git a/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerContext.java b/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerContext.java index 69080884..71a02101 100644 --- a/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerContext.java +++ b/src/main/java/org/shedlang/compiler/typechecker/TypeCheckerContext.java @@ -3,9 +3,7 @@ package org.shedlang.compiler.typechecker; import org.pcollections.Empty; import org.pcollections.PMap; import org.shedlang.compiler.ast.typed.FreeVariables; -import org.shedlang.compiler.types.NamespaceName; -import org.shedlang.compiler.types.NamespaceTypeInfo; -import org.shedlang.compiler.types.Type; +import org.shedlang.compiler.types.*; import org.shedlang.compiler.util.POrderedMap; import java.util.ArrayList; @@ -17,35 +15,49 @@ import java.util.function.BiFunction; public class TypeCheckerContext { public static final TypeCheckerContext EMPTY = new TypeCheckerContext( Empty.map(), + Effects.NONE, Set.of(), FreeVariables.builder(), Empty.map() ); private final PMap environment; + private final Effect effect; private final Set boundVariables; private final FreeVariables.Builder freeVariables; private final PMap namespaceTypeInfo; public TypeCheckerContext( PMap environment, + Effect effect, Set boundVariables, FreeVariables.Builder freeVariables, PMap namespaceTypeInfo ) { this.environment = environment; + this.effect = effect; this.boundVariables = boundVariables; this.freeVariables = freeVariables; this.namespaceTypeInfo = namespaceTypeInfo; } - public TypeCheckerContext enter(PMap environment) { + public TypeCheckerContext enterBlock(PMap environment) { + return enter(environment, this.effect); + } + + public TypeCheckerContext enterFunction(PMap environment, Effect effect) { + return enter(environment, effect); + } + + private TypeCheckerContext enter(PMap environment, Effect effect) { return new TypeCheckerContext( this.environment.plusAll(environment), + effect, environment.keySet(), FreeVariables.builder(), this.namespaceTypeInfo ); + } public TypeCheckerResult> runtimeLookup(String name) { @@ -58,10 +70,15 @@ public class TypeCheckerContext { public Optional compileTimeLookup(String name) { return Optional.ofNullable(environment.get(name)); } + + public Effect effect() { + return effect; + } private TypeCheckerContext withFreeVariable(String name) { return new TypeCheckerContext( environment, + this.effect, boundVariables, freeVariables.plus(name), this.namespaceTypeInfo @@ -80,6 +97,7 @@ public class TypeCheckerContext { return new TypeCheckerContext( this.environment, + this.effect, this.boundVariables, this.freeVariables, this.namespaceTypeInfo.plus(namespaceName, namespaceTypeInfo) diff --git a/src/main/java/org/shedlang/compiler/typechecker/errors/UnexpectedEffectError.java b/src/main/java/org/shedlang/compiler/typechecker/errors/UnexpectedEffectError.java new file mode 100644 index 00000000..3b617207 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/typechecker/errors/UnexpectedEffectError.java @@ -0,0 +1,24 @@ +package org.shedlang.compiler.typechecker.errors; + +import org.shedlang.compiler.errors.SourceError; +import org.shedlang.compiler.sources.Source; +import org.shedlang.compiler.types.Effect; + +public class UnexpectedEffectError extends SourceError { + private final Effect allowed; + private final Effect actual; + + public UnexpectedEffectError(Effect allowed, Effect actual, Source source) { + super("Allowed effect is " + allowed.describe() + " but was " + actual.describe(), source); + this.allowed = allowed; + this.actual = actual; + } + + public Effect allowed() { + return allowed; + } + + public Effect actual() { + return actual; + } +} -- cgit v1.2.3