Compare commits
4 Commits
5266e9b48e
...
4fb634aaa7
Author | SHA1 | Date |
---|---|---|
|
4fb634aaa7 | |
|
f65044c518 | |
|
1d47d7b850 | |
|
61624cd339 |
|
@ -207,12 +207,12 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
value: &Constant,
|
value: &Constant,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> Option<BasicValueEnum<'ctx>> {
|
||||||
match value {
|
match value {
|
||||||
Constant::Bool(v) => {
|
Constant::Bool(v) => {
|
||||||
assert!(self.unifier.unioned(ty, self.primitives.bool));
|
assert!(self.unifier.unioned(ty, self.primitives.bool));
|
||||||
let ty = self.ctx.i8_type();
|
let ty = self.ctx.i8_type();
|
||||||
ty.const_int(if *v { 1 } else { 0 }, false).into()
|
Some(ty.const_int(if *v { 1 } else { 0 }, false).into())
|
||||||
}
|
}
|
||||||
Constant::Int(val) => {
|
Constant::Int(val) => {
|
||||||
let ty = if self.unifier.unioned(ty, self.primitives.int32)
|
let ty = if self.unifier.unioned(ty, self.primitives.int32)
|
||||||
|
@ -226,28 +226,33 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
ty.const_int(*val as u64, false).into()
|
Some(ty.const_int(*val as u64, false).into())
|
||||||
}
|
}
|
||||||
Constant::Float(v) => {
|
Constant::Float(v) => {
|
||||||
assert!(self.unifier.unioned(ty, self.primitives.float));
|
assert!(self.unifier.unioned(ty, self.primitives.float));
|
||||||
let ty = self.ctx.f64_type();
|
let ty = self.ctx.f64_type();
|
||||||
ty.const_float(*v).into()
|
Some(ty.const_float(*v).into())
|
||||||
}
|
}
|
||||||
Constant::Tuple(v) => {
|
Constant::Tuple(v) => {
|
||||||
let ty = self.unifier.get_ty(ty);
|
let ty = self.unifier.get_ty(ty);
|
||||||
let types =
|
let types =
|
||||||
if let TypeEnum::TTuple { ty } = &*ty { ty.clone() } else { unreachable!() };
|
if let TypeEnum::TTuple { ty } = &*ty { ty.clone() } else { unreachable!() };
|
||||||
let values = zip(types.into_iter(), v.iter())
|
let values = zip(types.into_iter(), v.iter())
|
||||||
.map(|(ty, v)| self.gen_const(generator, v, ty))
|
.map_while(|(ty, v)| self.gen_const(generator, v, ty))
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
let types = values.iter().map(BasicValueEnum::get_type).collect_vec();
|
|
||||||
let ty = self.ctx.struct_type(&types, false);
|
if values.len() == v.len() {
|
||||||
ty.const_named_struct(&values).into()
|
let types = values.iter().map(BasicValueEnum::get_type).collect_vec();
|
||||||
|
let ty = self.ctx.struct_type(&types, false);
|
||||||
|
Some(ty.const_named_struct(&values).into())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Constant::Str(v) => {
|
Constant::Str(v) => {
|
||||||
assert!(self.unifier.unioned(ty, self.primitives.str));
|
assert!(self.unifier.unioned(ty, self.primitives.str));
|
||||||
if let Some(v) = self.const_strings.get(v) {
|
if let Some(v) = self.const_strings.get(v) {
|
||||||
*v
|
Some(*v)
|
||||||
} else {
|
} else {
|
||||||
let str_ptr =
|
let str_ptr =
|
||||||
self.builder.build_global_string_ptr(v, "const").as_pointer_value().into();
|
self.builder.build_global_string_ptr(v, "const").as_pointer_value().into();
|
||||||
|
@ -256,9 +261,22 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
let val =
|
let val =
|
||||||
ty.into_struct_type().const_named_struct(&[str_ptr, size.into()]).into();
|
ty.into_struct_type().const_named_struct(&[str_ptr, size.into()]).into();
|
||||||
self.const_strings.insert(v.to_string(), val);
|
self.const_strings.insert(v.to_string(), val);
|
||||||
val
|
Some(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Constant::Ellipsis => {
|
||||||
|
let msg = self.gen_string(generator, "");
|
||||||
|
|
||||||
|
self.raise_exn(
|
||||||
|
generator,
|
||||||
|
"0:NotImplementedError",
|
||||||
|
msg,
|
||||||
|
[None, None, None],
|
||||||
|
self.current_loc,
|
||||||
|
);
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -481,7 +499,7 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
|
||||||
generator: &mut dyn CodeGenerator,
|
generator: &mut dyn CodeGenerator,
|
||||||
s: S,
|
s: S,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
self.gen_const(generator, &nac3parser::ast::Constant::Str(s.into()), self.primitives.str)
|
self.gen_const(generator, &nac3parser::ast::Constant::Str(s.into()), self.primitives.str).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raise_exn(
|
pub fn raise_exn(
|
||||||
|
@ -1211,7 +1229,10 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>(
|
||||||
Ok(Some(match &expr.node {
|
Ok(Some(match &expr.node {
|
||||||
ExprKind::Constant { value, .. } => {
|
ExprKind::Constant { value, .. } => {
|
||||||
let ty = expr.custom.unwrap();
|
let ty = expr.custom.unwrap();
|
||||||
ctx.gen_const(generator, value, ty).into()
|
let Some(const_val) = ctx.gen_const(generator, value, ty) else {
|
||||||
|
return Ok(None)
|
||||||
|
};
|
||||||
|
const_val.into()
|
||||||
}
|
}
|
||||||
ExprKind::Name { id, .. } if id == &"none".into() => {
|
ExprKind::Name { id, .. } if id == &"none".into() => {
|
||||||
match (
|
match (
|
||||||
|
|
|
@ -604,7 +604,7 @@ pub fn exn_constructor<'ctx, 'a>(
|
||||||
let msg = if !args.is_empty() {
|
let msg = if !args.is_empty() {
|
||||||
args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.str)?
|
args.remove(0).1.to_basic_value_enum(ctx, generator, ctx.primitives.str)?
|
||||||
} else {
|
} else {
|
||||||
empty_string
|
empty_string.unwrap()
|
||||||
};
|
};
|
||||||
ctx.builder.build_store(ptr, msg);
|
ctx.builder.build_store(ptr, msg);
|
||||||
for i in [6, 7, 8].iter() {
|
for i in [6, 7, 8].iter() {
|
||||||
|
@ -627,7 +627,7 @@ pub fn exn_constructor<'ctx, 'a>(
|
||||||
&[zero, int32.const_int(*i, false)],
|
&[zero, int32.const_int(*i, false)],
|
||||||
"exn.str",
|
"exn.str",
|
||||||
);
|
);
|
||||||
ctx.builder.build_store(ptr, empty_string);
|
ctx.builder.build_store(ptr, empty_string.unwrap());
|
||||||
}
|
}
|
||||||
// set ints to zero
|
// set ints to zero
|
||||||
for i in [2, 3].iter() {
|
for i in [2, 3].iter() {
|
||||||
|
|
|
@ -361,7 +361,7 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s
|
||||||
pass
|
pass
|
||||||
"}
|
"}
|
||||||
],
|
],
|
||||||
vec!["application of type vars to generic class is not currently supported (at unknown: line 4 column 24)"];
|
vec!["application of type vars to generic class is not currently supported (at unknown:4:24)"];
|
||||||
"err no type var in generic app"
|
"err no type var in generic app"
|
||||||
)]
|
)]
|
||||||
#[test_case(
|
#[test_case(
|
||||||
|
@ -417,7 +417,7 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s
|
||||||
def __init__():
|
def __init__():
|
||||||
pass
|
pass
|
||||||
"}],
|
"}],
|
||||||
vec!["__init__ method must have a `self` parameter (at unknown: line 2 column 5)"];
|
vec!["__init__ method must have a `self` parameter (at unknown:2:5)"];
|
||||||
"err no self_1"
|
"err no self_1"
|
||||||
)]
|
)]
|
||||||
#[test_case(
|
#[test_case(
|
||||||
|
@ -439,7 +439,7 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s
|
||||||
"}
|
"}
|
||||||
|
|
||||||
],
|
],
|
||||||
vec!["a class definition can only have at most one base class declaration and one generic declaration (at unknown: line 1 column 24)"];
|
vec!["a class definition can only have at most one base class declaration and one generic declaration (at unknown:1:24)"];
|
||||||
"err multiple inheritance"
|
"err multiple inheritance"
|
||||||
)]
|
)]
|
||||||
#[test_case(
|
#[test_case(
|
||||||
|
@ -507,7 +507,7 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s
|
||||||
pass
|
pass
|
||||||
"}
|
"}
|
||||||
],
|
],
|
||||||
vec!["duplicate definition of class `A` (at unknown: line 1 column 1)"];
|
vec!["duplicate definition of class `A` (at unknown:1:1)"];
|
||||||
"class same name"
|
"class same name"
|
||||||
)]
|
)]
|
||||||
fn test_analyze(source: Vec<&str>, res: Vec<&str>) {
|
fn test_analyze(source: Vec<&str>, res: Vec<&str>) {
|
||||||
|
|
|
@ -13,8 +13,6 @@ pub enum TypeAnnotation {
|
||||||
// can only be CustomClassKind
|
// can only be CustomClassKind
|
||||||
Virtual(Box<TypeAnnotation>),
|
Virtual(Box<TypeAnnotation>),
|
||||||
TypeVar(Type),
|
TypeVar(Type),
|
||||||
/// A const generic variable.
|
|
||||||
ConstGeneric(Type),
|
|
||||||
/// A constant used in the context of a const-generic variable.
|
/// A constant used in the context of a const-generic variable.
|
||||||
Constant {
|
Constant {
|
||||||
/// The non-type variable associated with this constant.
|
/// The non-type variable associated with this constant.
|
||||||
|
@ -33,7 +31,7 @@ impl TypeAnnotation {
|
||||||
pub fn stringify(&self, unifier: &mut Unifier) -> String {
|
pub fn stringify(&self, unifier: &mut Unifier) -> String {
|
||||||
use TypeAnnotation::*;
|
use TypeAnnotation::*;
|
||||||
match self {
|
match self {
|
||||||
Primitive(ty) | TypeVar(ty) | ConstGeneric(ty) => unifier.stringify(*ty),
|
Primitive(ty) | TypeVar(ty) => unifier.stringify(*ty),
|
||||||
CustomClass { id, params } => {
|
CustomClass { id, params } => {
|
||||||
let class_name = match unifier.top_level {
|
let class_name = match unifier.top_level {
|
||||||
Some(ref top) => {
|
Some(ref top) => {
|
||||||
|
@ -329,6 +327,14 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
|
||||||
|
|
||||||
let value = SymbolValue::from_constant(value, underlying_ty, primitives, unifier)?;
|
let value = SymbolValue::from_constant(value, underlying_ty, primitives, unifier)?;
|
||||||
|
|
||||||
|
if matches!(value, SymbolValue::Str(_) | SymbolValue::Tuple(_) | SymbolValue::OptionSome(_)) {
|
||||||
|
return Err(format!(
|
||||||
|
"expression {} is not allowed for constant type annotation (at {})",
|
||||||
|
value.to_string(),
|
||||||
|
expr.location
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
Ok(TypeAnnotation::Constant {
|
Ok(TypeAnnotation::Constant {
|
||||||
ty: type_var,
|
ty: type_var,
|
||||||
value,
|
value,
|
||||||
|
@ -464,17 +470,17 @@ pub fn get_type_from_type_annotation_kinds(
|
||||||
}
|
}
|
||||||
Ok(ty)
|
Ok(ty)
|
||||||
}
|
}
|
||||||
TypeAnnotation::Primitive(ty) | TypeAnnotation::TypeVar(ty) | TypeAnnotation::ConstGeneric(ty) => Ok(*ty),
|
TypeAnnotation::Primitive(ty) | TypeAnnotation::TypeVar(ty) => Ok(*ty),
|
||||||
TypeAnnotation::Constant { ty, value, .. } => {
|
TypeAnnotation::Constant { ty, value, .. } => {
|
||||||
let ty_enum = unifier.get_ty(*ty);
|
let ty_enum = unifier.get_ty(*ty);
|
||||||
let (ty, name, loc) = match &*ty_enum {
|
let (ty, loc) = match &*ty_enum {
|
||||||
TypeEnum::TVar { range: ntv_underlying_ty, name, loc, is_const_generic: true, .. } => {
|
TypeEnum::TVar { range: ntv_underlying_ty, loc, is_const_generic: true, .. } => {
|
||||||
(ntv_underlying_ty[0], name, loc)
|
(ntv_underlying_ty[0], loc)
|
||||||
}
|
}
|
||||||
_ => unreachable!("{} ({})", unifier.stringify(*ty), ty_enum.get_type_name()),
|
_ => unreachable!("{} ({})", unifier.stringify(*ty), ty_enum.get_type_name()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let var = unifier.get_fresh_constant(value.clone(), ty, *name, *loc);
|
let var = unifier.get_fresh_constant(value.clone(), ty, *loc);
|
||||||
Ok(var)
|
Ok(var)
|
||||||
}
|
}
|
||||||
TypeAnnotation::Virtual(ty) => {
|
TypeAnnotation::Virtual(ty) => {
|
||||||
|
@ -551,7 +557,7 @@ pub fn get_type_var_contained_in_type_annotation(ann: &TypeAnnotation) -> Vec<Ty
|
||||||
result.extend(get_type_var_contained_in_type_annotation(a));
|
result.extend(get_type_var_contained_in_type_annotation(a));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeAnnotation::Primitive(..) | TypeAnnotation::ConstGeneric(..) | TypeAnnotation::Constant { .. } => {}
|
TypeAnnotation::Primitive(..) | TypeAnnotation::Constant { .. } => {}
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ impl<'a> Inferencer<'a> {
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
// there are some cases where the custom field is None
|
// there are some cases where the custom field is None
|
||||||
if let Some(ty) = &expr.custom {
|
if let Some(ty) = &expr.custom {
|
||||||
if !self.unifier.is_concrete(*ty, &self.function_data.bound_variables) {
|
if !matches!(&expr.node, ExprKind::Constant { value: Constant::Ellipsis, .. }) && !self.unifier.is_concrete(*ty, &self.function_data.bound_variables) {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"expected concrete type at {} but got {}",
|
"expected concrete type at {} but got {}",
|
||||||
expr.location,
|
expr.location,
|
||||||
|
|
|
@ -964,6 +964,7 @@ impl<'a> Inferencer<'a> {
|
||||||
ast::Constant::Str(_) => Ok(self.primitives.str),
|
ast::Constant::Str(_) => Ok(self.primitives.str),
|
||||||
ast::Constant::None
|
ast::Constant::None
|
||||||
=> report_error("CPython `None` not supported (nac3 uses `none` instead)", *loc),
|
=> report_error("CPython `None` not supported (nac3 uses `none` instead)", *loc),
|
||||||
|
ast::Constant::Ellipsis => Ok(self.unifier.get_fresh_var(None, None).0),
|
||||||
_ => report_error("not supported", *loc),
|
_ => report_error("not supported", *loc),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,7 +144,6 @@ pub enum TypeEnum {
|
||||||
value: SymbolValue,
|
value: SymbolValue,
|
||||||
/// The underlying type of the value.
|
/// The underlying type of the value.
|
||||||
ty: Type,
|
ty: Type,
|
||||||
name: Option<StrRef>,
|
|
||||||
loc: Option<Location>,
|
loc: Option<Location>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -372,12 +371,11 @@ impl Unifier {
|
||||||
&mut self,
|
&mut self,
|
||||||
value: SymbolValue,
|
value: SymbolValue,
|
||||||
ty: Type,
|
ty: Type,
|
||||||
name: Option<StrRef>,
|
|
||||||
loc: Option<Location>,
|
loc: Option<Location>,
|
||||||
) -> Type {
|
) -> Type {
|
||||||
assert!(matches!(self.get_ty(ty).as_ref(), TypeEnum::TObj { .. }));
|
assert!(matches!(self.get_ty(ty).as_ref(), TypeEnum::TObj { .. }));
|
||||||
|
|
||||||
self.add_ty(TypeEnum::TConstant { ty, value, name, loc })
|
self.add_ty(TypeEnum::TConstant { ty, value, loc })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unification would not unify rigid variables with other types, but we want to do this for
|
/// Unification would not unify rigid variables with other types, but we want to do this for
|
||||||
|
@ -1006,8 +1004,8 @@ impl Unifier {
|
||||||
};
|
};
|
||||||
n
|
n
|
||||||
}
|
}
|
||||||
TypeEnum::TConstant { value, name, .. } => {
|
TypeEnum::TConstant { value, .. } => {
|
||||||
format!("const[{}]", name.map(|n| format!("{n}={value}")).unwrap_or(value.to_string()))
|
format!("const({value})")
|
||||||
}
|
}
|
||||||
TypeEnum::TTuple { ty } => {
|
TypeEnum::TTuple { ty } => {
|
||||||
let mut fields =
|
let mut fields =
|
||||||
|
|
|
@ -9,7 +9,7 @@ import pathlib
|
||||||
|
|
||||||
from numpy import int32, int64, uint32, uint64
|
from numpy import int32, int64, uint32, uint64
|
||||||
from scipy import special
|
from scipy import special
|
||||||
from typing import TypeVar, Generic
|
from typing import TypeVar, Generic, Any
|
||||||
|
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
class Option(Generic[T]):
|
class Option(Generic[T]):
|
||||||
|
@ -94,11 +94,20 @@ def patch(module):
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def TypeVarDummy(zelf, name, *constraints):
|
||||||
|
if len(constraints) == 1:
|
||||||
|
zelf.__init_base__(name, *constraints, Any)
|
||||||
|
else:
|
||||||
|
zelf.__init_base__(name, *constraints)
|
||||||
|
|
||||||
module.int32 = int32
|
module.int32 = int32
|
||||||
module.int64 = int64
|
module.int64 = int64
|
||||||
module.uint32 = uint32
|
module.uint32 = uint32
|
||||||
module.uint64 = uint64
|
module.uint64 = uint64
|
||||||
module.TypeVar = TypeVar
|
module.TypeVar = TypeVar
|
||||||
|
module.ConstGeneric = TypeVar
|
||||||
|
module.ConstGeneric.__init_base__ = TypeVar.__init__
|
||||||
|
module.ConstGeneric.__init__ = TypeVarDummy
|
||||||
module.Generic = Generic
|
module.Generic = Generic
|
||||||
module.extern = extern
|
module.extern = extern
|
||||||
module.Option = Option
|
module.Option = Option
|
||||||
|
|
|
@ -1,31 +1,50 @@
|
||||||
A = NonTypeVar("A", int32)
|
A = ConstGeneric("A", int32)
|
||||||
B = NonTypeVar("B", uint32)
|
B = ConstGeneric("B", uint32)
|
||||||
|
T = TypeVar("T")
|
||||||
|
|
||||||
class NTGClass(Const[A]):
|
class ConstGenericClass(Generic[A]):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class NTG2Class(Const[A, B]):
|
class ConstGeneric2Class(Generic[A, B]):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@extern
|
class HybridGenericClass2(Generic[A, T]):
|
||||||
def make_ntg_2() -> NTGClass[2]:
|
|
||||||
...
|
|
||||||
|
|
||||||
@extern
|
|
||||||
def make_ntg2_1_2() -> NTG2Class[1, 2]:
|
|
||||||
...
|
|
||||||
|
|
||||||
def ntg(instance: NTGClass[2]):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def ntg2(instance: NTG2Class[1, 2]):
|
class HybridGenericClass3(Generic[T, A, B]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def make_generic_2() -> ConstGenericClass[2]:
|
||||||
|
return ...
|
||||||
|
|
||||||
|
def make_generic2_1_2() -> ConstGeneric2Class[1, 2]:
|
||||||
|
return ...
|
||||||
|
|
||||||
|
def make_hybrid_class_2_int32() -> HybridGenericClass2[2, int32]:
|
||||||
|
return ...
|
||||||
|
|
||||||
|
def make_hybrid_class_i32_0_1() -> HybridGenericClass3[int32, 0, 1]:
|
||||||
|
return ...
|
||||||
|
|
||||||
|
def consume_generic_2(instance: ConstGenericClass[2]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def consume_generic2_1_2(instance: ConstGeneric2Class[1, 2]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def consume_hybrid_class_2_i32(instance: HybridGenericClass2[2, int32]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def consume_hybrid_class_i32_0_1(instance: HybridGenericClass3[int32, 0, 1]):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def f():
|
def f():
|
||||||
ntg(make_ntg_2())
|
consume_generic_2(make_generic_2())
|
||||||
ntg2(make_ntg2_1_2())
|
consume_generic2_1_2(make_generic2_1_2())
|
||||||
|
consume_hybrid_class_2_i32(make_hybrid_class_2_int32())
|
||||||
|
consume_hybrid_class_i32_0_1(make_hybrid_class_i32_0_1())
|
||||||
|
|
||||||
def run() -> int32:
|
def run() -> int32:
|
||||||
return 0
|
return 0
|
|
@ -25,7 +25,7 @@ use nac3core::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use nac3parser::{
|
use nac3parser::{
|
||||||
ast::{Constant, Expr, ExprKind, StmtKind},
|
ast::{Constant, Expr, ExprKind, StmtKind, StrRef},
|
||||||
parser,
|
parser,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -76,13 +76,18 @@ fn handle_typevar_definition(
|
||||||
) -> Result<Type, String> {
|
) -> Result<Type, String> {
|
||||||
let ExprKind::Call { func, args, .. } = &var.node else {
|
let ExprKind::Call { func, args, .. } = &var.node else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"expression {:?} cannot be handled as a TypeVar in global scope",
|
"expression {:?} cannot be handled as a TypeVar or ConstGeneric in global scope",
|
||||||
var
|
var
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
match &func.node {
|
match &func.node {
|
||||||
ExprKind::Name { id, .. } if id == &"TypeVar".into() => {
|
ExprKind::Name { id, .. } if id == &"TypeVar".into() => {
|
||||||
|
let ExprKind::Constant { value: Constant::Str(ty_name), .. } = &args[0].node else {
|
||||||
|
unreachable!("Expected string constant for first parameter of `TypeVar`, got {:?}", &args[0].node)
|
||||||
|
};
|
||||||
|
let generic_name: StrRef = ty_name.to_string().into();
|
||||||
|
|
||||||
let constraints = args
|
let constraints = args
|
||||||
.iter()
|
.iter()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
|
@ -101,11 +106,27 @@ fn handle_typevar_definition(
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
Ok(unifier.get_fresh_var_with_range(&constraints, None, None).0)
|
let loc = func.location;
|
||||||
|
|
||||||
|
if constraints.len() == 1 {
|
||||||
|
return Err(format!("A single constraint is not allowed (at {})", loc))
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(unifier.get_fresh_var_with_range(&constraints, Some(generic_name), Some(loc)).0)
|
||||||
}
|
}
|
||||||
|
|
||||||
ExprKind::Name { id, .. } if id == &"NonTypeVar".into() => {
|
ExprKind::Name { id, .. } if id == &"ConstGeneric".into() => {
|
||||||
assert_eq!(args.len(), 2);
|
if args.len() != 2 {
|
||||||
|
return Err(format!("Expected 2 arguments for `ConstGeneric`, got {}", args.len()))
|
||||||
|
}
|
||||||
|
|
||||||
|
let ExprKind::Constant { value: Constant::Str(ty_name), .. } = &args[0].node else {
|
||||||
|
return Err(format!(
|
||||||
|
"Expected string constant for first parameter of `ConstGeneric`, got {:?}",
|
||||||
|
&args[0].node
|
||||||
|
))
|
||||||
|
};
|
||||||
|
let generic_name: StrRef = ty_name.to_string().into();
|
||||||
|
|
||||||
let ty = parse_ast_to_type_annotation_kinds(
|
let ty = parse_ast_to_type_annotation_kinds(
|
||||||
resolver,
|
resolver,
|
||||||
|
@ -119,11 +140,9 @@ fn handle_typevar_definition(
|
||||||
let constraint = get_type_from_type_annotation_kinds(
|
let constraint = get_type_from_type_annotation_kinds(
|
||||||
def_list, unifier, primitives, &ty, &mut None
|
def_list, unifier, primitives, &ty, &mut None
|
||||||
)?;
|
)?;
|
||||||
let ExprKind::Constant { value: Constant::Str(ty_name), .. } = &args[0].node else {
|
let loc = func.location;
|
||||||
unreachable!("Expected string constant for first parameter of `NonTypeVar`, got {:?}", &args[0].node)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(unifier.get_fresh_const_generic_var(constraint, Some(ty_name.to_string().into()), None).0)
|
Ok(unifier.get_fresh_const_generic_var(constraint, Some(generic_name), Some(loc)).0)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => Err(format!(
|
_ => Err(format!(
|
||||||
|
|
Loading…
Reference in New Issue