diff --git a/compiler/erg_compiler/context/compare.rs b/compiler/erg_compiler/context/compare.rs index 705ee5b3..1079a278 100644 --- a/compiler/erg_compiler/context/compare.rs +++ b/compiler/erg_compiler/context/compare.rs @@ -59,6 +59,7 @@ impl Context { } } (TyParam::MonoQVar(name), _other) | (_other, TyParam::MonoQVar(name)) => { + log!(err "comparing '{name} and {_other}"); panic!("Not instantiated type parameter: {name}") } (TyParam::UnaryOp { op: lop, val: lval }, TyParam::UnaryOp { op: rop, val: rval }) => { @@ -673,22 +674,44 @@ impl Context { } pub(crate) fn cyclic_supertype_of(&self, lhs: &FreeTyVar, rhs: &Type) -> bool { + let (_, ty_ctx) = self.get_nominal_type_ctx(rhs).unwrap(); + let subst_ctx = SubstContext::new(rhs, ty_ctx); // if `rhs` is {S: Str | ... }, `defined_rhs` will be Str - let defined_rhs = if let Some((defined_rhs, _)) = self.get_nominal_type_ctx(rhs) { - defined_rhs + let defined_rhs = if let Some((defined_rhs, _ty_ctx)) = self.get_nominal_type_ctx(rhs) { + if defined_rhs.has_qvar() { + subst_ctx + .substitute(defined_rhs.clone(), self, Location::Unknown) + .unwrap() + } else { + defined_rhs.clone() + } } else { return false; }; if let Some(super_traits) = self.get_nominal_super_trait_ctxs(rhs) { - for (sup_trait, _) in super_traits { - if self.sup_conforms(lhs, defined_rhs, sup_trait) { + for (sup_trait, _ty_ctx) in super_traits { + let sup_trait = if sup_trait.has_qvar() { + subst_ctx + .substitute(sup_trait.clone(), self, Location::Unknown) + .unwrap() + } else { + sup_trait.clone() + }; + if self.sup_conforms(lhs, &defined_rhs, &sup_trait) { return true; } } } if let Some(sup_classes) = self.get_nominal_super_class_ctxs(rhs) { - for (sup_class, _) in sup_classes { - if self.cyclic_supertype_of(lhs, sup_class) { + for (sup_class, _ty_ctx) in sup_classes { + let sup_class = if sup_class.has_qvar() { + subst_ctx + .substitute(sup_class.clone(), self, Location::Unknown) + .unwrap() + } else { + sup_class.clone() + }; + if self.cyclic_supertype_of(lhs, &sup_class) { return true; } } diff --git a/compiler/erg_compiler/context/eval.rs b/compiler/erg_compiler/context/eval.rs index cae8d3e7..3f5b9b3b 100644 --- a/compiler/erg_compiler/context/eval.rs +++ b/compiler/erg_compiler/context/eval.rs @@ -106,8 +106,13 @@ pub(crate) fn eval_lit(lit: &Literal) -> ValueObj { ValueObj::from_str(t, lit.token.content.clone()) } +/// Instantiate the polymorphic type from the quantified state. +/// +/// e.g. +/// ``` /// SubstContext::new(Array(?T, 0), Context(Array('T, 'N))) => SubstContext{ params: { 'T: ?T; 'N: 0 } } => ctx /// ctx.substitute(Array!('T; !'N)): Array(?T, !0) +/// ``` #[derive(Debug)] pub struct SubstContext { bounds: Set, @@ -125,6 +130,9 @@ impl fmt::Display for SubstContext { } impl SubstContext { + /// `substituted` is used to obtain real argument information. So it must be instantiated as `Array(?T, 0)` and so on. + /// + /// `ty_ctx` is used to obtain information on the names and variance of the parameters. pub fn new(substituted: &Type, ty_ctx: &Context) -> Self { let bounds = ty_ctx.type_params_bounds(); let param_names = ty_ctx.params.iter().map(|(opt_name, _)| { @@ -135,7 +143,7 @@ impl SubstContext { if param_names.len() != substituted.typarams().len() { let param_names = param_names.collect::>(); panic!( - "{param_names:?} != {}", + "{param_names:?} != [{}]", erg_common::fmt_vec(&substituted.typarams()) ); }