diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-07-02 13:13:58 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-07-02 13:13:58 +0100 |
| commit | 2e008d29e5d956f5463fa27c397f395a7e106d9e (patch) | |
| tree | 2c2febea1d0544aed1ff1d5d5a7c34ac3c94c22e /src/main/java | |
| parent | ff0b422cddead23865f0f5662bd9a4d2abef462d (diff) | |
Check call effect is sub-effect of function effect
Diffstat (limited to 'src/main/java')
4 files changed, 61 insertions, 7 deletions
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<String, Type> environment; + private final Effect effect; private final Set<String> boundVariables; private final FreeVariables.Builder freeVariables; private final PMap<NamespaceName, NamespaceTypeInfo> namespaceTypeInfo; public TypeCheckerContext( PMap<String, Type> environment, + Effect effect, Set<String> boundVariables, FreeVariables.Builder freeVariables, PMap<NamespaceName, NamespaceTypeInfo> namespaceTypeInfo ) { this.environment = environment; + this.effect = effect; this.boundVariables = boundVariables; this.freeVariables = freeVariables; this.namespaceTypeInfo = namespaceTypeInfo; } - public TypeCheckerContext enter(PMap<String, Type> environment) { + public TypeCheckerContext enterBlock(PMap<String, Type> environment) { + return enter(environment, this.effect); + } + + public TypeCheckerContext enterFunction(PMap<String, Type> environment, Effect effect) { + return enter(environment, effect); + } + + private TypeCheckerContext enter(PMap<String, Type> environment, Effect effect) { return new TypeCheckerContext( this.environment.plusAll(environment), + effect, environment.keySet(), FreeVariables.builder(), this.namespaceTypeInfo ); + } public TypeCheckerResult<Optional<Type>> runtimeLookup(String name) { @@ -58,10 +70,15 @@ public class TypeCheckerContext { public Optional<Type> 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; + } +} |
