SlideShare a Scribd company logo
1 of 26
Download to read offline
Eelco Visser
WG2.16 | Portland | February 2019
Statix: Declarative Type System Specification
Based on:

Van Antwerpen, Bach Poulsen, Rouvoet, Visser

Scopes as Types
PACMPL 2 (OOPSLA), 2018
Context
- Language workbench

- High-level language specification

- Abstract from implementation concerns (generate automatically)

Type systems
- Type constraints

- Name resolution => scope graphs

- Staging
!2
Type System Specification
Scope Graphs
!3
0A : MOD(1) B : MOD(2)
1 2
P P
I
q : BOOLp : BOOL
::
: :
module A {
import B
def p : bool = ~q
}
module B {
def q : bool = true
}
B
P*

$ < P
Statix By Example
4
Arithmetic Expressions: Concrete and Abstract Syntax
!5
context-free syntax // arithmetic
Exp.Int = <<INT>>
Exp.Add = <<Exp> + <Exp>> {left}
Exp.Sub = <<Exp> - <Exp>> {left}
Exp.Mul = <<Exp> * <Exp>> {left}
Exp.Eq = <<Exp> == <Exp>> {non-assoc}
constructors // arithmetic
Int : INT -> Exp
Add : Exp * Exp -> Exp
Sub : Exp * Exp -> Exp
Mul : Exp * Exp -> Exp
Eq : Exp * Exp -> Exp
SDF3 Statix
Program(
[Exp(
Add(Int("1"), Mul(Int("2"), Int("3")))
)]
)
> 1 + 2 * 3
Arithmetic Expressions: Abstract Syntax
!6
> 1 + 2 * 3
constructors // arithmetic
Int : INT -> Exp
Add : Exp * Exp -> Exp
Sub : Exp * Exp -> Exp
Mul : Exp * Exp -> Exp
Eq : Exp * Exp -> Exp
Arithmetic Expressions: Type Predicate
!7
> 1 + 2 * 3
sorts TYPE constructors
INT : TYPE
BOOL : TYPE
FUN : TYPE * TYPE -> TYPE
rules // expressions
typeOfExp : scope * Exp -> TYPE
typeOfExp(s, Int(i)) = INT().
typeOfExp(s, Add(e1, e2)) = INT() :-
typeOfExp(s, e1) == INT(),
typeOfExp(s, e2) == INT().
. . .
typeOfExp(s, Eq(e1, e2)) = BOOL() :- {T}
typeOfExp(s, e1) == T,
typeOfExp(s, e2) == T.
constructors // arithmetic
Int : INT -> Exp
Add : Exp * Exp -> Exp
Sub : Exp * Exp -> Exp
Mul : Exp * Exp -> Exp
Eq : Exp * Exp -> Exp
Variable Definitions
!8
sorts Program constructors
Program : list(Decl) -> Program
sorts Decl constructors
Def : Bind -> Decl
Exp : Exp -> Decl
sorts Bind constructors
Bind : ID * Exp -> Bind
TBind : ID * Type * Exp -> Bind
relations
typeOfDecl : occurrence -> TYPE
def a = 0
def b = a + c
def b = 1 + d
def c : Int = 0
def e : Bool = 1
> a + b + c
Variable Definitions
!9
sorts Program constructors
Program : list(Decl) -> Program
sorts Decl constructors
Def : Bind -> Decl
Exp : Exp -> Decl
sorts Bind constructors
Bind : ID * Exp -> Bind
TBind : ID * Type * Exp -> Bind
relations
typeOfDecl : occurrence -> TYPE
rules
programOK : Program
programOK(Program(decls)) :- {s}
new s,
declsOk(s, decls).
rules // declarations
declOk : scope * Decl
declsOk maps declOk(*, list(*))
declOk(s, Def(bind)) :-
bindOk(s, s, bind).
declOk(s, Exp(e)) :- {T}
typeOfExp(s, e) == T.
def a = 0
def b = a + c
def b = 1 + d
def c : Int = 0
def e : Bool = 1
> a + b + c
Variable Definitions: Declarations
!10
sorts Program constructors
Program : list(Decl) -> Program
sorts Decl constructors
Def : Bind -> Decl
Exp : Exp -> Decl
sorts Bind constructors
Bind : ID * Exp -> Bind
TBind : ID * Type * Exp -> Bind
relations
typeOfDecl : occurrence -> TYPE
def a = 0
def b = a + c
def b = 1 + d
def c : Int = 0
def e : Bool = 1
> a + b + c
rules // bindings
bindOk : scope * scope * Bind
bindsOk maps bindOk(*, *, list(*))
bindOk(s_bnd, s_ctx, Bind(x, e)) :- {T}
typeOfExp(s_ctx, e) == T,
s_bnd -> Var{x@x} with typeOfDecl T.
bindOk(s_bnd, s_ctx, TBind(x, t, e)) :- {T}
typeOfType(s_ctx, t) == T,
typeOfExp(s_ctx, e) == T,
s_bnd -> Var{x@x} with typeOfDecl T.
Variable Definitions: Name Resolution
!11
rules // bindings
bindOk : scope * scope * Bind
bindsOk maps bindOk(*, *, list(*))
bindOk(s_bnd, s_ctx, Bind(x, e)) :- {T}
typeOfExp(s_ctx, e) == T,
s_bnd -> Var{x@x} with typeOfDecl T.
bindOk(s_bnd, s_ctx, TBind(x, t, e)) :- {T}
typeOfType(s_ctx, t) == T,
typeOfExp(s_ctx, e) == T,
s_bnd -> Var{x@x} with typeOfDecl T.
rules // variables
typeOfExp(s, Var(x)) = T :- {p d }
typeOfDecl of Var{x@x} in s |-> [(p, (d, T))].
sorts Program constructors
Program : list(Decl) -> Program
sorts Decl constructors
Def : Bind -> Decl
Exp : Exp -> Decl
sorts Bind constructors
Bind : ID * Exp -> Bind
TBind : ID * Type * Exp -> Bind
relations
typeOfDecl : occurrence -> TYPE
def a = 0
def b = a + c
def b = 1 + d
def c : Int = 0
def e : Bool = 1
> a + b + c
Lexical Scope: Functions
!12
rules // functions
typeOfExp(s, Fun(x, t, e)) = FUN(T, S) :- {s_fun}
typeOfType(s, t) == T,
new s_fun,
s_fun -P-> s,
s_fun -> Var{x@x} with typeOfDecl T,
typeOfExp(s_fun, e) == S.
typeOfExp(s, App(e1, e2)) = T :- {S}
typeOfExp(s, e1) == FUN(S, T),
typeOfExp(s, e2) == S.
sorts TYPE constructors
INT : TYPE
BOOL : TYPE
FUN : TYPE * TYPE -> TYPE
def i = 3
def inc = fun(x : Int) { x + i }
> inc 2
constructors // functions
Fun : ID * Type * Exp -> Exp
App : Exp * Exp -> Exp
Lexical Scope: Sequential Let
!13
rules // let bindings
typeOfExp(s, Let(binds, e)) = T :- {s_let}
new s_let,
sbindsOk(s, s_let, binds),
typeOfExp(s_let, e) == T.
def a = 0
def b = 1
def c = 2
> let
a = c;
b = a;
c = b
in
a + b + c
rules // bindings
sbindsOk : scope * scope * list(Bind)
sbindsOk(s, s_fin, []) :-
s_fin -P-> s.
sbindsOk(s, s_fin, [bind | binds]) :- {s_mid}
new s_mid, s_mid -P-> s,
bindOk(s_mid, s, bind),
sbindsOk(s_mid, s_fin, binds).
Lexical Scope: Parallel Let
!14
rules // let bindings
typeOfExp(s, LetPar(binds, e)) = T :- {s_let}
new s_let, s_let -P-> s,
bindsOk(s_let, s, binds),
typeOfExp(s_let, e) == T.
bindOk : scope * scope * Bind
bindsOk maps bindOk(*, *, list(*))
bindOk(s_bnd, s_ctx, Bind(x, e)) :- {T}
typeOfExp(s_ctx, e) == T,
s_bnd -> Var{x@x} with typeOfDecl T.
def a = 0
def b = 1
def c = 2
> letpar
a = c;
b = a;
c = b
in
a + b + c
Lexical Scope: Recursive Let
!15
rules // let bindings
typeOfExp(s, LetRec(binds, e)) = T :- {s_let}
new s_let, s_let -P-> s,
bindsOk(s_let, s_let, binds),
typeOfExp(s_let, e) == T.
bindOk : scope * scope * Bind
bindsOk maps bindOk(*, *, list(*))
bindOk(s_bnd, s_ctx, Bind(x, e)) :- {T}
typeOfExp(s_ctx, e) == T,
s_bnd -> Var{x@x} with typeOfDecl T.
> letrec
odd = fun(x : Int) {
if x == 0 then false
else even(x - 1)
};
even = fun(x : Int) {
if x == 0 then true
else odd(x - 1)
}
in
even(3)
Modules
!16
module A {
import B
def a = 4
def c = b + 4
}
module B {
import A
def b = a + 3
}
Modules: Scopes as Types
!17
rules // modules
declOk(s, Module(m, decls)) :- {s_mod}
new s_mod, s_mod -P-> s,
s -> Mod{m@m} with typeOfDecl MOD(s_mod),
declsOk(s_mod, decls).
declOk(s, Import(m)) :- {p d s_mod}
typeOfDecl of Mod{m@m} in s |-> [(p, (d, MOD(s_mod)))],
s -I-> s_mod.
module A {
import B
def a = 4
def c = b + 4
}
module B {
import A
def b = a + 3
}
sorts TYPE constructors
INT : TYPE
BOOL : TYPE
FUN : TYPE * TYPE -> TYPE
MOD : scope -> TYPE
name-resolution
labels P I R
resolve Var filter pathMatch[P* (R* | I*)]
min pathLt[$ < I, $ < P, I < P, R < P]
resolve Mod filter pathMatch[P P* I*]
min pathLt[$ < I, $ < P, I < P, R < P]
Records
!18
record Point {
x : Int
y : Int
}
def p : Point
= new Point { x = 1, y = 2}
> p.x + p.y
def z = 3
> with p do x + y + z
Record Type Declaration: Scopes as Types
!19
rules // record type
declOk(s, Record(x, fdecls)) :- {s_rec}
new s_rec,
fdeclsOk(s_rec, s, fdecls),
s -> Var{x@x} with typeOfDecl REC(s_rec).
fdeclOk : scope * scope * FDecl
fdeclsOk maps fdeclOk(*, *, list(*))
fdeclOk(s_bnd, s_ctx, FDecl(x, t)) :- {T}
typeOfType(s_ctx, t) == T,
s_bnd -> Var{x@x} with typeOfDecl T.
sorts TYPE constructors
INT : TYPE
BOOL : TYPE
FUN : TYPE * TYPE -> TYPE
REC : scope -> TYPE
record Point {
x : Int
y : Int
}
def p : Point
= new Point { x = 1, y = 2}
> p.x + p.y
def z = 3
> with p do x + y + z
Record Literals
!20
rules // records construction
typeOfExp(s, New(x, fbinds)) = REC(s_rec) :- {p d}
typeOfDecl of Var{x@x} in s |-> [(p, (d, REC(s_rec)))],
fbindsOk(s, s_rec, fbinds).
fbindOk : scope * scope * FBind
fbindsOk maps fbindOk(*, *, list(*))
fbindOk(s, s_rec, FBind(x, e)) :- {p d T}
typeOfExp(s, e) == T,
typeOfDecl of Var{x@x} in s_rec |-> [(p, (d, T))].
record Point {
x : Int
y : Int
}
def p : Point
= new Point { x = 1, y = 2}
> p.x + p.y
def z = 3
> with p do x + y + z
sorts TYPE constructors
INT : TYPE
BOOL : TYPE
FUN : TYPE * TYPE -> TYPE
REC : scope -> TYPE
Record Projection
!21
rules // record projection
typeOfExp(s, Proj(e, x)) = T :- {p d s_rec S}
typeOfExp(s, e) == S,
proj(S, x) == T.
proj : TYPE * ID -> TYPE
proj(REC(s_rec), x) = T :- {p d}
typeOfDecl of Var{x@x} in s_rec |-> [(p, (d, T))].
record Point {
x : Int
y : Int
}
def p : Point
= new Point { x = 1, y = 2}
> p.x + p.y
def z = 3
> with p do x + y + z
sorts TYPE constructors
INT : TYPE
BOOL : TYPE
FUN : TYPE * TYPE -> TYPE
REC : scope -> TYPE
With Record
!22
rules // with record value
typeOfExp(s, With(e1, e2)) = T :- {s_with s_rec}
typeOfExp(s, e1) == REC(s_rec),
new s_with,
s_with -P-> s, s_with -R-> s_rec,
typeOfExp(s_with, e2) == T.
record Point {
x : Int
y : Int
}
def p : Point
= new Point { x = 1, y = 2}
> p.x + p.y
def z = 3
> with p do x + y + z
sorts TYPE constructors
INT : TYPE
BOOL : TYPE
FUN : TYPE * TYPE -> TYPE
REC : scope -> TYPE
name-resolution
labels P I R
resolve Var filter pathMatch[P* (R* | I*)]
min pathLt[$ < I, $ < P, I < P, R < P]
Type References
!23
record Point {
x : Int
y : Int
}
def translate : Point -> Point -> Point
= fun(p: Point){ fun(d: Point) {
new Point{
x = p.x + d.x,
y = p.y + d.y }
} }
def p : Point = new Point { x = 1, y = 2}
> translate(p)(p)
rules // types
typeOfType : scope * Type -> TYPE
typeOfType(s, IntT()) = INT().
typeOfType(s, BoolT()) = BOOL().
typeOfType(s, FunT(t1, t2)) =
FUN(typeOfType(s, t1), typeOfType(s, t2)).
typeOfType(s, RecT(x)) = REC(s_rec) :- {p d}
typeOfDecl of Var{x@x}
in s |-> [(p, (d, REC(s_rec)))].
What Else
24
Implementation
!25
type point = {x : num, y : num} in
let mkpoint = fun(x : num) { {x = x, y = x} } in
type color = num in
type colorpoint =
{k : color} extends point in
let addColor =
fun(c : num) {
fun(p : colorpoint) {
({c = c} extends p) : colorpoint
}
} in
(addColor 6 ({c = 5} extends mkpoint 4)) : colorpoint
typeOfExp : scope * Exp -> Type
typeOfExp(s, Num(_)) = NUM().
typeOfExp(s, Plus(e1, e2)) = NUM() :-
typeOfExp(s, e1) == NUM(),
typeOfExp(s, e2) == NUM().
typeOfExp(s, Fun(x, te, e)) = FUN(S, T) :- {s_fun}
typeOfTypeExp(s, te) == S,
new s_fun, s_fun -P-> s,
s_fun -> Var{x@x} with typeOfDecl S,
typeOfExp(s_fun, e) == T.
typeOfExp(s, Var(x)) = T :-
query typeOfDecl filter pathMatch[P*(R|E)*] and { d :- varOrFld(x, d) }
min pathLt[$ < P, $ < R, $ < E, R < P, R < E] and true
in s |-> [(_, (_, T))].
typeOfExp(s, App(e1, e2)) = T :- {S U}
typeOfExp(s, e1) == FUN(S, T),
typeOfExp(s, e2) == U,
subType(U, S).
type point = {x : num, y : num} in
let mkpoint = fun(x : num) { {x = x, y = x} } in
type color = num in
type colorpoint =
{k : color} extends point in
let addColor =
fun(c : num) {
fun(p : colorpoint) {
({c = c} extends p) : colorpoint
}
} in
(addColor 6 ({c = 5} extends mkpoint 4)) : colorpoint
Program
Statix Specification
Typed Program
Solver
package mb.statix.solver;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.immutables.value.Value;
import org.metaborg.util.functions.Predicate1;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import mb.nabl2.terms.ITerm;
import mb.nabl2.terms.ITermVar;
import mb.nabl2.terms.unification.IUnifier;
import mb.nabl2.util.TermFormatter;
import mb.statix.solver.log.IDebugContext;
import mb.statix.solver.log.LazyDebugContext;
import mb.statix.solver.log.Log;
public class Solver {
private Solver() {
}
public static SolverResult solve(final State state, final Iterable<IConstraint> constraints,
final Completeness completeness, final IDebugContext debug) throws InterruptedException {
return solve(state, constraints, completeness, v -> false, s -> false, debug);
}
public static SolverResult solve(final State _state, final Iterable<IConstraint> _constraints,
final Completeness _completeness, Predicate1<ITermVar> isRigid, Predicate1<ITerm> isClosed,
final IDebugContext debug) throws InterruptedException {
debug.info("Solving constraints");
final LazyDebugContext proxyDebug = new LazyDebugContext(debug);
// set-up
final Set<IConstraint> constraints = Sets.newConcurrentHashSet(_constraints);
State state = _state;
Completeness completeness = _completeness;
completeness = completeness.addAll(constraints);
// fixed point
final Set<IConstraint> failed = Sets.newHashSet();
final Log delayedLog = new Log();
final Map<IConstraint, Delay> delays = Maps.newHashMap();
boolean progress = true;
int reduced = 0;
int delayed = 0;
outer: while(progress) {
progress = false;
delayedLog.clear();
delays.clear();
final Iterator<IConstraint> it = constraints.iterator();
while(it.hasNext()) {
if(Thread.interrupted()) {
throw new InterruptedException();
}
final IConstraint constraint = it.next();
proxyDebug.info("Solving {}", constraint.toString(Solver.shallowTermFormatter(state.unifier())));
IDebugContext subDebug = proxyDebug.subContext();
try {
Optional<ConstraintResult> maybeResult =
constraint.solve(state, new ConstraintContext(completeness, isRigid, isClosed, subDebug));
progress = true;
it.remove();
completeness = completeness.remove(constraint);
reduced += 1;
if(maybeResult.isPresent()) {
final ConstraintResult result = maybeResult.get();
state = result.state();
if(!result.constraints().isEmpty()) {
final List<IConstraint> newConstaints = result.constraints().stream()
.map(c -> c.withCause(constraint)).collect(Collectors.toList());
subDebug.info("Simplified to {}", toString(newConstaints, state.unifier()));
constraints.addAll(newConstaints);
completeness = completeness.addAll(newConstaints);
}
} else {
subDebug.error("Failed");
failed.add(constraint);
if(proxyDebug.isRoot()) {
printTrace(constraint, state.unifier(), subDebug);
} else {
proxyDebug.info("Break early because of errors.");
break outer;
}
}
proxyDebug.commit();
} catch(Delay d) {
subDebug.info("Delayed");
delayedLog.absorb(proxyDebug.clear());
delays.put(constraint, d);
delayed += 1;
}
}
}
delayedLog.flush(debug);
debug.info("Solved {} constraints ({} delays) with {} failed and {} remaining constraint(s).", reduced, delayed,
failed.size(), constraints.size());
return SolverResult.of(state, completeness, failed, delays);
}
public static Optional<SolverResult> entails(final State state, final Iterable<IConstraint> constraints,
final Completeness completeness, final IDebugContext debug) throws InterruptedException, Delay {
return entails(state, constraints, completeness, ImmutableSet.of(), debug);
}
public static Optional<SolverResult> entails(final State state, final Iterable<IConstraint> constraints,
final Completeness completeness, final Iterable<ITermVar> _localVars, final IDebugContext debug)
throws InterruptedException, Delay {
debug.info("Checking entailment of {}", toString(constraints, state.unifier()));
final Set<ITermVar> localVars = ImmutableSet.copyOf(_localVars);
final Set<ITermVar> rigidVars = Sets.difference(state.vars(), localVars);
final SolverResult result = Solver.solve(state, constraints, completeness, rigidVars::contains,
state.scopes()::contains, debug.subContext());
if(result.hasErrors()) {
debug.info("Constraints not entailed");
return Optional.empty();
} else if(result.delays().isEmpty()) {
debug.info("Constraints entailed");
return Optional.of(result);
} else {
debug.info("Cannot decide constraint entailment (unsolved constraints)");
throw result.delay(); // FIXME Remove local vars and scopes
}
}
private static void printTrace(IConstraint failed, IUnifier unifier, IDebugContext debug) {
@Nullable IConstraint constraint = failed;
while(constraint != null) {
debug.error(" * {}", constraint.toString(Solver.shallowTermFormatter(unifier)));
constraint = constraint.cause().orElse(null);
}
}
private static String toString(Iterable<IConstraint> constraints, IUnifier unifier) {
final StringBuilder sb = new StringBuilder();
boolean first = true;
for(IConstraint constraint : constraints) {
if(first) {
first = false;
} else {
sb.append(", ");
}
sb.append(constraint.toString(Solver.shallowTermFormatter(unifier)));
}
return sb.toString();
}
@Value.Immutable
public static abstract class ASolverResult {
@Value.Parameter public abstract State state();
@Value.Parameter public abstract Completeness completeness();
@Value.Parameter public abstract Set<IConstraint> errors();
public boolean hasErrors() {
return !errors().isEmpty();
}
@Value.Parameter public abstract Map<IConstraint, Delay> delays();
public Delay delay() {
ImmutableSet.Builder<ITermVar> vars = ImmutableSet.builder();
ImmutableMultimap.Builder<ITerm, ITerm> scopes = ImmutableMultimap.builder();
delays().values().stream().forEach(d -> {
vars.addAll(d.vars());
scopes.putAll(d.scopes());
});
return new Delay(vars.build(), scopes.build());
}
}
public static TermFormatter shallowTermFormatter(final IUnifier unifier) {
return t -> unifier.toString(t, 3);
}
}
Scope Graph
In the paper
- Typing rules for STLC+records, System F, Featherweight Java

- Resolution calculus of scope graphs

- Declarative semantics of Statix

- Description of solver algorithm of Statix

In the artifact
- Implementation of scope graphs and Statix

- Executable specs of STLC+records, System F, Featherweight
Generic Java
!26
Other Contributions

More Related Content

What's hot

Functional programming in Python
Functional programming in PythonFunctional programming in Python
Functional programming in Python
Colin Su
 
FP 201 - Unit 6
FP 201 - Unit 6FP 201 - Unit 6
FP 201 - Unit 6
rohassanie
 

What's hot (20)

CS4200 2019 | Lecture 3 | Parsing
CS4200 2019 | Lecture 3 | ParsingCS4200 2019 | Lecture 3 | Parsing
CS4200 2019 | Lecture 3 | Parsing
 
Writing Parsers and Compilers with PLY
Writing Parsers and Compilers with PLYWriting Parsers and Compilers with PLY
Writing Parsers and Compilers with PLY
 
Compiler Construction | Lecture 12 | Virtual Machines
Compiler Construction | Lecture 12 | Virtual MachinesCompiler Construction | Lecture 12 | Virtual Machines
Compiler Construction | Lecture 12 | Virtual Machines
 
Declare Your Language: Type Checking
Declare Your Language: Type CheckingDeclare Your Language: Type Checking
Declare Your Language: Type Checking
 
Declare Your Language: Transformation by Strategic Term Rewriting
Declare Your Language: Transformation by Strategic Term RewritingDeclare Your Language: Transformation by Strategic Term Rewriting
Declare Your Language: Transformation by Strategic Term Rewriting
 
Declare Your Language: Name Resolution
Declare Your Language: Name ResolutionDeclare Your Language: Name Resolution
Declare Your Language: Name Resolution
 
Что нам готовит грядущий C#7?
Что нам готовит грядущий C#7?Что нам готовит грядущий C#7?
Что нам готовит грядущий C#7?
 
Compiler Construction | Lecture 3 | Syntactic Editor Services
Compiler Construction | Lecture 3 | Syntactic Editor ServicesCompiler Construction | Lecture 3 | Syntactic Editor Services
Compiler Construction | Lecture 3 | Syntactic Editor Services
 
C++11
C++11C++11
C++11
 
Chapter 22. Lambda Expressions and LINQ
Chapter 22. Lambda Expressions and LINQChapter 22. Lambda Expressions and LINQ
Chapter 22. Lambda Expressions and LINQ
 
C++11 & C++14
C++11 & C++14C++11 & C++14
C++11 & C++14
 
Declare Your Language: Syntax Definition
Declare Your Language: Syntax DefinitionDeclare Your Language: Syntax Definition
Declare Your Language: Syntax Definition
 
C++11
C++11C++11
C++11
 
Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]
Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]
Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]
 
Fp201 unit5 1
Fp201 unit5 1Fp201 unit5 1
Fp201 unit5 1
 
Lex (lexical analyzer)
Lex (lexical analyzer)Lex (lexical analyzer)
Lex (lexical analyzer)
 
Functional programming in Python
Functional programming in PythonFunctional programming in Python
Functional programming in Python
 
Fp201 unit4
Fp201 unit4Fp201 unit4
Fp201 unit4
 
FP 201 - Unit 6
FP 201 - Unit 6FP 201 - Unit 6
FP 201 - Unit 6
 
C++ 11 Features
C++ 11 FeaturesC++ 11 Features
C++ 11 Features
 

Similar to Declarative Type System Specification with Statix

仕事で使うF#
仕事で使うF#仕事で使うF#
仕事で使うF#
bleis tift
 
Model-Driven Software Development - Static Analysis & Error Checking
Model-Driven Software Development - Static Analysis & Error CheckingModel-Driven Software Development - Static Analysis & Error Checking
Model-Driven Software Development - Static Analysis & Error Checking
Eelco Visser
 
Intermediate code generation1
Intermediate code generation1Intermediate code generation1
Intermediate code generation1
Shashwat Shriparv
 
Arrays and structures
Arrays and structuresArrays and structures
Arrays and structures
Mohd Arif
 
Automatically Describing Program Structure and Behavior (PhD Defense)
Automatically Describing Program Structure and Behavior (PhD Defense)Automatically Describing Program Structure and Behavior (PhD Defense)
Automatically Describing Program Structure and Behavior (PhD Defense)
Ray Buse
 

Similar to Declarative Type System Specification with Statix (20)

仕事で使うF#
仕事で使うF#仕事で使うF#
仕事で使うF#
 
Ch8a
Ch8aCh8a
Ch8a
 
Python cheatsheat.pdf
Python cheatsheat.pdfPython cheatsheat.pdf
Python cheatsheat.pdf
 
Compiling fµn language
Compiling fµn languageCompiling fµn language
Compiling fµn language
 
Model-Driven Software Development - Static Analysis & Error Checking
Model-Driven Software Development - Static Analysis & Error CheckingModel-Driven Software Development - Static Analysis & Error Checking
Model-Driven Software Development - Static Analysis & Error Checking
 
Intermediate code generation1
Intermediate code generation1Intermediate code generation1
Intermediate code generation1
 
Munihac 2018 - Beautiful Template Haskell
Munihac 2018 - Beautiful Template HaskellMunihac 2018 - Beautiful Template Haskell
Munihac 2018 - Beautiful Template Haskell
 
CPP Homework help
CPP Homework helpCPP Homework help
CPP Homework help
 
chapter1.ppt
chapter1.pptchapter1.ppt
chapter1.ppt
 
Arrays and structures
Arrays and structuresArrays and structures
Arrays and structures
 
Declarative Semantics Definition - Term Rewriting
Declarative Semantics Definition - Term RewritingDeclarative Semantics Definition - Term Rewriting
Declarative Semantics Definition - Term Rewriting
 
Syntaxdirected
SyntaxdirectedSyntaxdirected
Syntaxdirected
 
Syntaxdirected
SyntaxdirectedSyntaxdirected
Syntaxdirected
 
Syntaxdirected (1)
Syntaxdirected (1)Syntaxdirected (1)
Syntaxdirected (1)
 
Automatically Describing Program Structure and Behavior (PhD Defense)
Automatically Describing Program Structure and Behavior (PhD Defense)Automatically Describing Program Structure and Behavior (PhD Defense)
Automatically Describing Program Structure and Behavior (PhD Defense)
 
Scala by Luc Duponcheel
Scala by Luc DuponcheelScala by Luc Duponcheel
Scala by Luc Duponcheel
 
Cheatsheet_Python.pdf
Cheatsheet_Python.pdfCheatsheet_Python.pdf
Cheatsheet_Python.pdf
 
Frsa
FrsaFrsa
Frsa
 
Array
ArrayArray
Array
 
Chapter2
Chapter2Chapter2
Chapter2
 

More from Eelco Visser

More from Eelco Visser (16)

CS4200 2019 Lecture 1: Introduction
CS4200 2019 Lecture 1: IntroductionCS4200 2019 Lecture 1: Introduction
CS4200 2019 Lecture 1: Introduction
 
A Direct Semantics of Declarative Disambiguation Rules
A Direct Semantics of Declarative Disambiguation RulesA Direct Semantics of Declarative Disambiguation Rules
A Direct Semantics of Declarative Disambiguation Rules
 
Compiler Construction | Lecture 17 | Beyond Compiler Construction
Compiler Construction | Lecture 17 | Beyond Compiler ConstructionCompiler Construction | Lecture 17 | Beyond Compiler Construction
Compiler Construction | Lecture 17 | Beyond Compiler Construction
 
Domain Specific Languages for Parallel Graph AnalytiX (PGX)
Domain Specific Languages for Parallel Graph AnalytiX (PGX)Domain Specific Languages for Parallel Graph AnalytiX (PGX)
Domain Specific Languages for Parallel Graph AnalytiX (PGX)
 
Compiler Construction | Lecture 15 | Memory Management
Compiler Construction | Lecture 15 | Memory ManagementCompiler Construction | Lecture 15 | Memory Management
Compiler Construction | Lecture 15 | Memory Management
 
Compiler Construction | Lecture 13 | Code Generation
Compiler Construction | Lecture 13 | Code GenerationCompiler Construction | Lecture 13 | Code Generation
Compiler Construction | Lecture 13 | Code Generation
 
Compiler Construction | Lecture 11 | Monotone Frameworks
Compiler Construction | Lecture 11 | Monotone FrameworksCompiler Construction | Lecture 11 | Monotone Frameworks
Compiler Construction | Lecture 11 | Monotone Frameworks
 
Compiler Construction | Lecture 10 | Data-Flow Analysis
Compiler Construction | Lecture 10 | Data-Flow AnalysisCompiler Construction | Lecture 10 | Data-Flow Analysis
Compiler Construction | Lecture 10 | Data-Flow Analysis
 
Compiler Construction | Lecture 7 | Type Checking
Compiler Construction | Lecture 7 | Type CheckingCompiler Construction | Lecture 7 | Type Checking
Compiler Construction | Lecture 7 | Type Checking
 
Compiler Construction | Lecture 6 | Introduction to Static Analysis
Compiler Construction | Lecture 6 | Introduction to Static AnalysisCompiler Construction | Lecture 6 | Introduction to Static Analysis
Compiler Construction | Lecture 6 | Introduction to Static Analysis
 
Compiler Construction | Lecture 4 | Parsing
Compiler Construction | Lecture 4 | Parsing Compiler Construction | Lecture 4 | Parsing
Compiler Construction | Lecture 4 | Parsing
 
Compiler Construction | Lecture 1 | What is a compiler?
Compiler Construction | Lecture 1 | What is a compiler?Compiler Construction | Lecture 1 | What is a compiler?
Compiler Construction | Lecture 1 | What is a compiler?
 
Declare Your Language: Virtual Machines & Code Generation
Declare Your Language: Virtual Machines & Code GenerationDeclare Your Language: Virtual Machines & Code Generation
Declare Your Language: Virtual Machines & Code Generation
 
Declare Your Language: Dynamic Semantics
Declare Your Language: Dynamic SemanticsDeclare Your Language: Dynamic Semantics
Declare Your Language: Dynamic Semantics
 
Declare Your Language: Constraint Resolution 2
Declare Your Language: Constraint Resolution 2Declare Your Language: Constraint Resolution 2
Declare Your Language: Constraint Resolution 2
 
Declare Your Language: Constraint Resolution 1
Declare Your Language: Constraint Resolution 1Declare Your Language: Constraint Resolution 1
Declare Your Language: Constraint Resolution 1
 

Recently uploaded

AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
VictorSzoltysek
 

Recently uploaded (20)

How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptxBUS PASS MANGEMENT SYSTEM USING PHP.pptx
BUS PASS MANGEMENT SYSTEM USING PHP.pptx
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
The Guide to Integrating Generative AI into Unified Continuous Testing Platfo...
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdfThe Top App Development Trends Shaping the Industry in 2024-25 .pdf
The Top App Development Trends Shaping the Industry in 2024-25 .pdf
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
ManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide DeckManageIQ - Sprint 236 Review - Slide Deck
ManageIQ - Sprint 236 Review - Slide Deck
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfAzure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 

Declarative Type System Specification with Statix

  • 1. Eelco Visser WG2.16 | Portland | February 2019 Statix: Declarative Type System Specification Based on: Van Antwerpen, Bach Poulsen, Rouvoet, Visser Scopes as Types PACMPL 2 (OOPSLA), 2018
  • 2. Context - Language workbench - High-level language specification - Abstract from implementation concerns (generate automatically) Type systems - Type constraints - Name resolution => scope graphs - Staging !2 Type System Specification
  • 3. Scope Graphs !3 0A : MOD(1) B : MOD(2) 1 2 P P I q : BOOLp : BOOL :: : : module A { import B def p : bool = ~q } module B { def q : bool = true } B P* $ < P
  • 5. Arithmetic Expressions: Concrete and Abstract Syntax !5 context-free syntax // arithmetic Exp.Int = <<INT>> Exp.Add = <<Exp> + <Exp>> {left} Exp.Sub = <<Exp> - <Exp>> {left} Exp.Mul = <<Exp> * <Exp>> {left} Exp.Eq = <<Exp> == <Exp>> {non-assoc} constructors // arithmetic Int : INT -> Exp Add : Exp * Exp -> Exp Sub : Exp * Exp -> Exp Mul : Exp * Exp -> Exp Eq : Exp * Exp -> Exp SDF3 Statix Program( [Exp( Add(Int("1"), Mul(Int("2"), Int("3"))) )] ) > 1 + 2 * 3
  • 6. Arithmetic Expressions: Abstract Syntax !6 > 1 + 2 * 3 constructors // arithmetic Int : INT -> Exp Add : Exp * Exp -> Exp Sub : Exp * Exp -> Exp Mul : Exp * Exp -> Exp Eq : Exp * Exp -> Exp
  • 7. Arithmetic Expressions: Type Predicate !7 > 1 + 2 * 3 sorts TYPE constructors INT : TYPE BOOL : TYPE FUN : TYPE * TYPE -> TYPE rules // expressions typeOfExp : scope * Exp -> TYPE typeOfExp(s, Int(i)) = INT(). typeOfExp(s, Add(e1, e2)) = INT() :- typeOfExp(s, e1) == INT(), typeOfExp(s, e2) == INT(). . . . typeOfExp(s, Eq(e1, e2)) = BOOL() :- {T} typeOfExp(s, e1) == T, typeOfExp(s, e2) == T. constructors // arithmetic Int : INT -> Exp Add : Exp * Exp -> Exp Sub : Exp * Exp -> Exp Mul : Exp * Exp -> Exp Eq : Exp * Exp -> Exp
  • 8. Variable Definitions !8 sorts Program constructors Program : list(Decl) -> Program sorts Decl constructors Def : Bind -> Decl Exp : Exp -> Decl sorts Bind constructors Bind : ID * Exp -> Bind TBind : ID * Type * Exp -> Bind relations typeOfDecl : occurrence -> TYPE def a = 0 def b = a + c def b = 1 + d def c : Int = 0 def e : Bool = 1 > a + b + c
  • 9. Variable Definitions !9 sorts Program constructors Program : list(Decl) -> Program sorts Decl constructors Def : Bind -> Decl Exp : Exp -> Decl sorts Bind constructors Bind : ID * Exp -> Bind TBind : ID * Type * Exp -> Bind relations typeOfDecl : occurrence -> TYPE rules programOK : Program programOK(Program(decls)) :- {s} new s, declsOk(s, decls). rules // declarations declOk : scope * Decl declsOk maps declOk(*, list(*)) declOk(s, Def(bind)) :- bindOk(s, s, bind). declOk(s, Exp(e)) :- {T} typeOfExp(s, e) == T. def a = 0 def b = a + c def b = 1 + d def c : Int = 0 def e : Bool = 1 > a + b + c
  • 10. Variable Definitions: Declarations !10 sorts Program constructors Program : list(Decl) -> Program sorts Decl constructors Def : Bind -> Decl Exp : Exp -> Decl sorts Bind constructors Bind : ID * Exp -> Bind TBind : ID * Type * Exp -> Bind relations typeOfDecl : occurrence -> TYPE def a = 0 def b = a + c def b = 1 + d def c : Int = 0 def e : Bool = 1 > a + b + c rules // bindings bindOk : scope * scope * Bind bindsOk maps bindOk(*, *, list(*)) bindOk(s_bnd, s_ctx, Bind(x, e)) :- {T} typeOfExp(s_ctx, e) == T, s_bnd -> Var{x@x} with typeOfDecl T. bindOk(s_bnd, s_ctx, TBind(x, t, e)) :- {T} typeOfType(s_ctx, t) == T, typeOfExp(s_ctx, e) == T, s_bnd -> Var{x@x} with typeOfDecl T.
  • 11. Variable Definitions: Name Resolution !11 rules // bindings bindOk : scope * scope * Bind bindsOk maps bindOk(*, *, list(*)) bindOk(s_bnd, s_ctx, Bind(x, e)) :- {T} typeOfExp(s_ctx, e) == T, s_bnd -> Var{x@x} with typeOfDecl T. bindOk(s_bnd, s_ctx, TBind(x, t, e)) :- {T} typeOfType(s_ctx, t) == T, typeOfExp(s_ctx, e) == T, s_bnd -> Var{x@x} with typeOfDecl T. rules // variables typeOfExp(s, Var(x)) = T :- {p d } typeOfDecl of Var{x@x} in s |-> [(p, (d, T))]. sorts Program constructors Program : list(Decl) -> Program sorts Decl constructors Def : Bind -> Decl Exp : Exp -> Decl sorts Bind constructors Bind : ID * Exp -> Bind TBind : ID * Type * Exp -> Bind relations typeOfDecl : occurrence -> TYPE def a = 0 def b = a + c def b = 1 + d def c : Int = 0 def e : Bool = 1 > a + b + c
  • 12. Lexical Scope: Functions !12 rules // functions typeOfExp(s, Fun(x, t, e)) = FUN(T, S) :- {s_fun} typeOfType(s, t) == T, new s_fun, s_fun -P-> s, s_fun -> Var{x@x} with typeOfDecl T, typeOfExp(s_fun, e) == S. typeOfExp(s, App(e1, e2)) = T :- {S} typeOfExp(s, e1) == FUN(S, T), typeOfExp(s, e2) == S. sorts TYPE constructors INT : TYPE BOOL : TYPE FUN : TYPE * TYPE -> TYPE def i = 3 def inc = fun(x : Int) { x + i } > inc 2 constructors // functions Fun : ID * Type * Exp -> Exp App : Exp * Exp -> Exp
  • 13. Lexical Scope: Sequential Let !13 rules // let bindings typeOfExp(s, Let(binds, e)) = T :- {s_let} new s_let, sbindsOk(s, s_let, binds), typeOfExp(s_let, e) == T. def a = 0 def b = 1 def c = 2 > let a = c; b = a; c = b in a + b + c rules // bindings sbindsOk : scope * scope * list(Bind) sbindsOk(s, s_fin, []) :- s_fin -P-> s. sbindsOk(s, s_fin, [bind | binds]) :- {s_mid} new s_mid, s_mid -P-> s, bindOk(s_mid, s, bind), sbindsOk(s_mid, s_fin, binds).
  • 14. Lexical Scope: Parallel Let !14 rules // let bindings typeOfExp(s, LetPar(binds, e)) = T :- {s_let} new s_let, s_let -P-> s, bindsOk(s_let, s, binds), typeOfExp(s_let, e) == T. bindOk : scope * scope * Bind bindsOk maps bindOk(*, *, list(*)) bindOk(s_bnd, s_ctx, Bind(x, e)) :- {T} typeOfExp(s_ctx, e) == T, s_bnd -> Var{x@x} with typeOfDecl T. def a = 0 def b = 1 def c = 2 > letpar a = c; b = a; c = b in a + b + c
  • 15. Lexical Scope: Recursive Let !15 rules // let bindings typeOfExp(s, LetRec(binds, e)) = T :- {s_let} new s_let, s_let -P-> s, bindsOk(s_let, s_let, binds), typeOfExp(s_let, e) == T. bindOk : scope * scope * Bind bindsOk maps bindOk(*, *, list(*)) bindOk(s_bnd, s_ctx, Bind(x, e)) :- {T} typeOfExp(s_ctx, e) == T, s_bnd -> Var{x@x} with typeOfDecl T. > letrec odd = fun(x : Int) { if x == 0 then false else even(x - 1) }; even = fun(x : Int) { if x == 0 then true else odd(x - 1) } in even(3)
  • 16. Modules !16 module A { import B def a = 4 def c = b + 4 } module B { import A def b = a + 3 }
  • 17. Modules: Scopes as Types !17 rules // modules declOk(s, Module(m, decls)) :- {s_mod} new s_mod, s_mod -P-> s, s -> Mod{m@m} with typeOfDecl MOD(s_mod), declsOk(s_mod, decls). declOk(s, Import(m)) :- {p d s_mod} typeOfDecl of Mod{m@m} in s |-> [(p, (d, MOD(s_mod)))], s -I-> s_mod. module A { import B def a = 4 def c = b + 4 } module B { import A def b = a + 3 } sorts TYPE constructors INT : TYPE BOOL : TYPE FUN : TYPE * TYPE -> TYPE MOD : scope -> TYPE name-resolution labels P I R resolve Var filter pathMatch[P* (R* | I*)] min pathLt[$ < I, $ < P, I < P, R < P] resolve Mod filter pathMatch[P P* I*] min pathLt[$ < I, $ < P, I < P, R < P]
  • 18. Records !18 record Point { x : Int y : Int } def p : Point = new Point { x = 1, y = 2} > p.x + p.y def z = 3 > with p do x + y + z
  • 19. Record Type Declaration: Scopes as Types !19 rules // record type declOk(s, Record(x, fdecls)) :- {s_rec} new s_rec, fdeclsOk(s_rec, s, fdecls), s -> Var{x@x} with typeOfDecl REC(s_rec). fdeclOk : scope * scope * FDecl fdeclsOk maps fdeclOk(*, *, list(*)) fdeclOk(s_bnd, s_ctx, FDecl(x, t)) :- {T} typeOfType(s_ctx, t) == T, s_bnd -> Var{x@x} with typeOfDecl T. sorts TYPE constructors INT : TYPE BOOL : TYPE FUN : TYPE * TYPE -> TYPE REC : scope -> TYPE record Point { x : Int y : Int } def p : Point = new Point { x = 1, y = 2} > p.x + p.y def z = 3 > with p do x + y + z
  • 20. Record Literals !20 rules // records construction typeOfExp(s, New(x, fbinds)) = REC(s_rec) :- {p d} typeOfDecl of Var{x@x} in s |-> [(p, (d, REC(s_rec)))], fbindsOk(s, s_rec, fbinds). fbindOk : scope * scope * FBind fbindsOk maps fbindOk(*, *, list(*)) fbindOk(s, s_rec, FBind(x, e)) :- {p d T} typeOfExp(s, e) == T, typeOfDecl of Var{x@x} in s_rec |-> [(p, (d, T))]. record Point { x : Int y : Int } def p : Point = new Point { x = 1, y = 2} > p.x + p.y def z = 3 > with p do x + y + z sorts TYPE constructors INT : TYPE BOOL : TYPE FUN : TYPE * TYPE -> TYPE REC : scope -> TYPE
  • 21. Record Projection !21 rules // record projection typeOfExp(s, Proj(e, x)) = T :- {p d s_rec S} typeOfExp(s, e) == S, proj(S, x) == T. proj : TYPE * ID -> TYPE proj(REC(s_rec), x) = T :- {p d} typeOfDecl of Var{x@x} in s_rec |-> [(p, (d, T))]. record Point { x : Int y : Int } def p : Point = new Point { x = 1, y = 2} > p.x + p.y def z = 3 > with p do x + y + z sorts TYPE constructors INT : TYPE BOOL : TYPE FUN : TYPE * TYPE -> TYPE REC : scope -> TYPE
  • 22. With Record !22 rules // with record value typeOfExp(s, With(e1, e2)) = T :- {s_with s_rec} typeOfExp(s, e1) == REC(s_rec), new s_with, s_with -P-> s, s_with -R-> s_rec, typeOfExp(s_with, e2) == T. record Point { x : Int y : Int } def p : Point = new Point { x = 1, y = 2} > p.x + p.y def z = 3 > with p do x + y + z sorts TYPE constructors INT : TYPE BOOL : TYPE FUN : TYPE * TYPE -> TYPE REC : scope -> TYPE name-resolution labels P I R resolve Var filter pathMatch[P* (R* | I*)] min pathLt[$ < I, $ < P, I < P, R < P]
  • 23. Type References !23 record Point { x : Int y : Int } def translate : Point -> Point -> Point = fun(p: Point){ fun(d: Point) { new Point{ x = p.x + d.x, y = p.y + d.y } } } def p : Point = new Point { x = 1, y = 2} > translate(p)(p) rules // types typeOfType : scope * Type -> TYPE typeOfType(s, IntT()) = INT(). typeOfType(s, BoolT()) = BOOL(). typeOfType(s, FunT(t1, t2)) = FUN(typeOfType(s, t1), typeOfType(s, t2)). typeOfType(s, RecT(x)) = REC(s_rec) :- {p d} typeOfDecl of Var{x@x} in s |-> [(p, (d, REC(s_rec)))].
  • 25. Implementation !25 type point = {x : num, y : num} in let mkpoint = fun(x : num) { {x = x, y = x} } in type color = num in type colorpoint = {k : color} extends point in let addColor = fun(c : num) { fun(p : colorpoint) { ({c = c} extends p) : colorpoint } } in (addColor 6 ({c = 5} extends mkpoint 4)) : colorpoint typeOfExp : scope * Exp -> Type typeOfExp(s, Num(_)) = NUM(). typeOfExp(s, Plus(e1, e2)) = NUM() :- typeOfExp(s, e1) == NUM(), typeOfExp(s, e2) == NUM(). typeOfExp(s, Fun(x, te, e)) = FUN(S, T) :- {s_fun} typeOfTypeExp(s, te) == S, new s_fun, s_fun -P-> s, s_fun -> Var{x@x} with typeOfDecl S, typeOfExp(s_fun, e) == T. typeOfExp(s, Var(x)) = T :- query typeOfDecl filter pathMatch[P*(R|E)*] and { d :- varOrFld(x, d) } min pathLt[$ < P, $ < R, $ < E, R < P, R < E] and true in s |-> [(_, (_, T))]. typeOfExp(s, App(e1, e2)) = T :- {S U} typeOfExp(s, e1) == FUN(S, T), typeOfExp(s, e2) == U, subType(U, S). type point = {x : num, y : num} in let mkpoint = fun(x : num) { {x = x, y = x} } in type color = num in type colorpoint = {k : color} extends point in let addColor = fun(c : num) { fun(p : colorpoint) { ({c = c} extends p) : colorpoint } } in (addColor 6 ({c = 5} extends mkpoint 4)) : colorpoint Program Statix Specification Typed Program Solver package mb.statix.solver; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Nullable; import org.immutables.value.Value; import org.metaborg.util.functions.Predicate1; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import mb.nabl2.terms.ITerm; import mb.nabl2.terms.ITermVar; import mb.nabl2.terms.unification.IUnifier; import mb.nabl2.util.TermFormatter; import mb.statix.solver.log.IDebugContext; import mb.statix.solver.log.LazyDebugContext; import mb.statix.solver.log.Log; public class Solver { private Solver() { } public static SolverResult solve(final State state, final Iterable<IConstraint> constraints, final Completeness completeness, final IDebugContext debug) throws InterruptedException { return solve(state, constraints, completeness, v -> false, s -> false, debug); } public static SolverResult solve(final State _state, final Iterable<IConstraint> _constraints, final Completeness _completeness, Predicate1<ITermVar> isRigid, Predicate1<ITerm> isClosed, final IDebugContext debug) throws InterruptedException { debug.info("Solving constraints"); final LazyDebugContext proxyDebug = new LazyDebugContext(debug); // set-up final Set<IConstraint> constraints = Sets.newConcurrentHashSet(_constraints); State state = _state; Completeness completeness = _completeness; completeness = completeness.addAll(constraints); // fixed point final Set<IConstraint> failed = Sets.newHashSet(); final Log delayedLog = new Log(); final Map<IConstraint, Delay> delays = Maps.newHashMap(); boolean progress = true; int reduced = 0; int delayed = 0; outer: while(progress) { progress = false; delayedLog.clear(); delays.clear(); final Iterator<IConstraint> it = constraints.iterator(); while(it.hasNext()) { if(Thread.interrupted()) { throw new InterruptedException(); } final IConstraint constraint = it.next(); proxyDebug.info("Solving {}", constraint.toString(Solver.shallowTermFormatter(state.unifier()))); IDebugContext subDebug = proxyDebug.subContext(); try { Optional<ConstraintResult> maybeResult = constraint.solve(state, new ConstraintContext(completeness, isRigid, isClosed, subDebug)); progress = true; it.remove(); completeness = completeness.remove(constraint); reduced += 1; if(maybeResult.isPresent()) { final ConstraintResult result = maybeResult.get(); state = result.state(); if(!result.constraints().isEmpty()) { final List<IConstraint> newConstaints = result.constraints().stream() .map(c -> c.withCause(constraint)).collect(Collectors.toList()); subDebug.info("Simplified to {}", toString(newConstaints, state.unifier())); constraints.addAll(newConstaints); completeness = completeness.addAll(newConstaints); } } else { subDebug.error("Failed"); failed.add(constraint); if(proxyDebug.isRoot()) { printTrace(constraint, state.unifier(), subDebug); } else { proxyDebug.info("Break early because of errors."); break outer; } } proxyDebug.commit(); } catch(Delay d) { subDebug.info("Delayed"); delayedLog.absorb(proxyDebug.clear()); delays.put(constraint, d); delayed += 1; } } } delayedLog.flush(debug); debug.info("Solved {} constraints ({} delays) with {} failed and {} remaining constraint(s).", reduced, delayed, failed.size(), constraints.size()); return SolverResult.of(state, completeness, failed, delays); } public static Optional<SolverResult> entails(final State state, final Iterable<IConstraint> constraints, final Completeness completeness, final IDebugContext debug) throws InterruptedException, Delay { return entails(state, constraints, completeness, ImmutableSet.of(), debug); } public static Optional<SolverResult> entails(final State state, final Iterable<IConstraint> constraints, final Completeness completeness, final Iterable<ITermVar> _localVars, final IDebugContext debug) throws InterruptedException, Delay { debug.info("Checking entailment of {}", toString(constraints, state.unifier())); final Set<ITermVar> localVars = ImmutableSet.copyOf(_localVars); final Set<ITermVar> rigidVars = Sets.difference(state.vars(), localVars); final SolverResult result = Solver.solve(state, constraints, completeness, rigidVars::contains, state.scopes()::contains, debug.subContext()); if(result.hasErrors()) { debug.info("Constraints not entailed"); return Optional.empty(); } else if(result.delays().isEmpty()) { debug.info("Constraints entailed"); return Optional.of(result); } else { debug.info("Cannot decide constraint entailment (unsolved constraints)"); throw result.delay(); // FIXME Remove local vars and scopes } } private static void printTrace(IConstraint failed, IUnifier unifier, IDebugContext debug) { @Nullable IConstraint constraint = failed; while(constraint != null) { debug.error(" * {}", constraint.toString(Solver.shallowTermFormatter(unifier))); constraint = constraint.cause().orElse(null); } } private static String toString(Iterable<IConstraint> constraints, IUnifier unifier) { final StringBuilder sb = new StringBuilder(); boolean first = true; for(IConstraint constraint : constraints) { if(first) { first = false; } else { sb.append(", "); } sb.append(constraint.toString(Solver.shallowTermFormatter(unifier))); } return sb.toString(); } @Value.Immutable public static abstract class ASolverResult { @Value.Parameter public abstract State state(); @Value.Parameter public abstract Completeness completeness(); @Value.Parameter public abstract Set<IConstraint> errors(); public boolean hasErrors() { return !errors().isEmpty(); } @Value.Parameter public abstract Map<IConstraint, Delay> delays(); public Delay delay() { ImmutableSet.Builder<ITermVar> vars = ImmutableSet.builder(); ImmutableMultimap.Builder<ITerm, ITerm> scopes = ImmutableMultimap.builder(); delays().values().stream().forEach(d -> { vars.addAll(d.vars()); scopes.putAll(d.scopes()); }); return new Delay(vars.build(), scopes.build()); } } public static TermFormatter shallowTermFormatter(final IUnifier unifier) { return t -> unifier.toString(t, 3); } } Scope Graph
  • 26. In the paper - Typing rules for STLC+records, System F, Featherweight Java - Resolution calculus of scope graphs - Declarative semantics of Statix - Description of solver algorithm of Statix In the artifact - Implementation of scope graphs and Statix - Executable specs of STLC+records, System F, Featherweight Generic Java !26 Other Contributions