diff --git a/artiq/compiler/builtins.py b/artiq/compiler/builtins.py index efac80e9a..1a5cc3670 100644 --- a/artiq/compiler/builtins.py +++ b/artiq/compiler/builtins.py @@ -201,9 +201,8 @@ def is_collection(typ): types.is_mono(typ, "list") def is_allocated(typ): - return typ.fold(False, lambda accum, typ: - accum or not (is_none(typ) or is_bool(typ) or is_int(typ) or - is_float(typ) or is_range(typ) or - types.is_c_function(typ) or types.is_rpc_function(typ) or - types.is_method(typ) or - types.is_value(typ))) + return not (is_none(typ) or is_bool(typ) or is_int(typ) or + is_float(typ) or is_range(typ) or + types.is_c_function(typ) or types.is_rpc_function(typ) or + types.is_method(typ) or types.is_tuple(typ) or + types.is_value(typ)) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 30c821082..5a101cdec 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1411,15 +1411,15 @@ class ARTIQIRGenerator(algorithm.Visitor): return ir.Constant(None, builtins.TNone()) elif types.is_exn_constructor(typ): return self.alloc_exn(node.type, *[self.visit(arg_node) for arg_node in node.args]) + elif types.is_constructor(typ): + return self.append(ir.Alloc([], typ.instance)) else: assert False def visit_CallT(self, node): typ = node.func.type.find() - if types.is_constructor(typ) and not types.is_exn_constructor(typ): - return self.append(ir.Alloc([], typ.instance)) - elif types.is_builtin(typ): + if types.is_builtin(typ): return self.visit_builtin_call(node) else: if types.is_function(typ): diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 8711aeedf..93a5c2c7e 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -705,6 +705,12 @@ class Inferencer(algorithm.Visitor): pass else: diagnose(valid_forms()) + elif types.is_constructor(typ): + # An user-defined class. + self._unify(node.type, typ.find().instance, + node.loc, None) + else: + assert False def visit_CallT(self, node): self.generic_visit(node) @@ -722,10 +728,6 @@ class Inferencer(algorithm.Visitor): if types.is_var(typ): return # not enough info yet - elif types.is_constructor(typ) and not types.is_exn_constructor(typ): - self._unify(node.type, typ.find().instance, - node.loc, None) - return elif types.is_builtin(typ): return self.visit_builtin_call(node) elif not (types.is_function(typ) or types.is_method(typ)): diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 981d76305..e32e49d8f 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -391,7 +391,7 @@ class LLVMIRGenerator: assert llinsn is not None self.llmap[insn] = llinsn - if insn.loc is not None: + if insn.loc is not None and not isinstance(llinsn, ll.Constant): diloc = self.debug_info_emitter.emit_loc(insn.loc, disubprogram) llinsn.set_metadata('dbg', diloc) diff --git a/artiq/compiler/types.py b/artiq/compiler/types.py index 0226d8fe9..34a86dd11 100644 --- a/artiq/compiler/types.py +++ b/artiq/compiler/types.py @@ -99,8 +99,8 @@ class TMono(Type): attributes = OrderedDict() def __init__(self, name, params={}): - assert isinstance(params, dict) - self.name, self.params = name, params + assert isinstance(params, (dict, OrderedDict)) + self.name, self.params = name, OrderedDict(sorted(params.items())) def find(self): return self diff --git a/artiq/compiler/validators/escape.py b/artiq/compiler/validators/escape.py index 9fc053fe6..386cd388b 100644 --- a/artiq/compiler/validators/escape.py +++ b/artiq/compiler/validators/escape.py @@ -7,6 +7,9 @@ import functools from pythonparser import algorithm, diagnostic from .. import asttyped, types, builtins +def has_region(typ): + return typ.fold(False, lambda accum, typ: accum or builtins.is_allocated(typ)) + class Region: """ A last-in-first-out allocation region. Tied to lexical scoping @@ -78,7 +81,7 @@ class RegionOf(algorithm.Visitor): # Value lives as long as the current scope, if it's mutable, # or else forever def visit_sometimes_allocating(self, node): - if builtins.is_allocated(node.type): + if has_region(node.type): return self.youngest_region else: return None @@ -89,7 +92,7 @@ class RegionOf(algorithm.Visitor): # Value lives as long as the object/container, if it's mutable, # or else forever def visit_accessor(self, node): - if builtins.is_allocated(node.type): + if has_region(node.type): return self.visit(node.value) else: return None @@ -131,7 +134,7 @@ class RegionOf(algorithm.Visitor): # Value lives forever def visit_immutable(self, node): - assert not builtins.is_allocated(node.type) + assert not has_region(node.type) return None visit_NameConstantT = visit_immutable @@ -217,7 +220,7 @@ class EscapeValidator(algorithm.Visitor): self.youngest_env = {} for name in typing_env: - if builtins.is_allocated(typing_env[name]): + if has_region(typing_env[name]): self.youngest_env[name] = Region(None) # not yet known else: self.youngest_env[name] = None # lives forever diff --git a/lit-test/test/inferencer/class.py b/lit-test/test/inferencer/class.py index 2efdf1561..455f3e810 100644 --- a/lit-test/test/inferencer/class.py +++ b/lit-test/test/inferencer/class.py @@ -15,5 +15,5 @@ c.a # CHECK-L: .f:()->NoneType c.f -# CHECK-L: .m:method(self=c, fn=(self:c)->NoneType) +# CHECK-L: .m:method(fn=(self:c)->NoneType, self=c) c().m()