aboutsummaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-07-02 13:13:58 +0100
committerMichael Williamson <mike@zwobble.org>2023-07-02 13:13:58 +0100
commit2e008d29e5d956f5463fa27c397f395a7e106d9e (patch)
tree2c2febea1d0544aed1ff1d5d5a7c34ac3c94c22e /src/main/java
parentff0b422cddead23865f0f5662bd9a4d2abef462d (diff)
Check call effect is sub-effect of function effect
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/org/shedlang/compiler/ShedCompiler.java2
-rw-r--r--src/main/java/org/shedlang/compiler/typechecker/TypeChecker.java16
-rw-r--r--src/main/java/org/shedlang/compiler/typechecker/TypeCheckerContext.java26
-rw-r--r--src/main/java/org/shedlang/compiler/typechecker/errors/UnexpectedEffectError.java24
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;
+ }
+}