diff --git a/compiler/erg_compiler/context/instantiate.rs b/compiler/erg_compiler/context/instantiate.rs index c1561fbc..8ad73b62 100644 --- a/compiler/erg_compiler/context/instantiate.rs +++ b/compiler/erg_compiler/context/instantiate.rs @@ -767,14 +767,23 @@ impl Context { &self, p: &ParamTySpec, opt_decl_t: Option<&ParamTy>, + default_t: Option<&TypeSpec>, tmp_tv_ctx: Option<&TyVarInstContext>, mode: RegistrationMode, ) -> TyCheckResult { let t = self.instantiate_typespec(&p.ty, opt_decl_t, tmp_tv_ctx, mode)?; - Ok(ParamTy::pos( - p.name.as_ref().map(|t| t.inspect().to_owned()), - t, - )) + if let Some(default_t) = default_t { + Ok(ParamTy::kw_default( + p.name.as_ref().unwrap().inspect().to_owned(), + t, + self.instantiate_typespec(default_t, opt_decl_t, tmp_tv_ctx, mode)?, + )) + } else { + Ok(ParamTy::pos( + p.name.as_ref().map(|t| t.inspect().to_owned()), + t, + )) + } } pub(crate) fn instantiate_typespec( @@ -854,15 +863,23 @@ impl Context { } TypeSpec::Subr(subr) => { let non_defaults = try_map_mut(subr.non_defaults.iter(), |p| { - self.instantiate_func_param_spec(p, opt_decl_t, tmp_tv_ctx, mode) + self.instantiate_func_param_spec(p, opt_decl_t, None, tmp_tv_ctx, mode) })?; let var_args = subr .var_args .as_ref() - .map(|p| self.instantiate_func_param_spec(p, opt_decl_t, tmp_tv_ctx, mode)) + .map(|p| { + self.instantiate_func_param_spec(p, opt_decl_t, None, tmp_tv_ctx, mode) + }) .transpose()?; let defaults = try_map_mut(subr.defaults.iter(), |p| { - self.instantiate_func_param_spec(p, opt_decl_t, tmp_tv_ctx, mode) + self.instantiate_func_param_spec( + &p.param, + opt_decl_t, + Some(&p.default), + tmp_tv_ctx, + mode, + ) })? .into_iter() .collect(); diff --git a/compiler/erg_parser/ast.rs b/compiler/erg_parser/ast.rs index ffd4dc1f..fd3ed429 100644 --- a/compiler/erg_parser/ast.rs +++ b/compiler/erg_parser/ast.rs @@ -1591,13 +1591,31 @@ impl ParamTySpec { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct DefaultParamTySpec { + pub param: ParamTySpec, + pub default: TypeSpec, +} + +impl fmt::Display for DefaultParamTySpec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} := {}", self.param, self.default) + } +} + +impl DefaultParamTySpec { + pub const fn new(param: ParamTySpec, default: TypeSpec) -> Self { + Self { param, default } + } +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct SubrTypeSpec { pub bounds: TypeBoundSpecs, pub lparen: Option, pub non_defaults: Vec, pub var_args: Option>, - pub defaults: Vec, + pub defaults: Vec, pub arrow: Token, pub return_t: Box, } @@ -1638,7 +1656,7 @@ impl SubrTypeSpec { lparen: Option, non_defaults: Vec, var_args: Option, - defaults: Vec, + defaults: Vec, arrow: Token, return_t: TypeSpec, ) -> Self { diff --git a/compiler/erg_parser/parse.rs b/compiler/erg_parser/parse.rs index a2517c61..06349ca4 100644 --- a/compiler/erg_parser/parse.rs +++ b/compiler/erg_parser/parse.rs @@ -2813,12 +2813,18 @@ impl Parser { for param in lambda.sig.params.defaults.into_iter() { let param = match (param.sig.pat, param.sig.t_spec) { (ParamPattern::VarName(name), Some(t_spec_with_op)) => { - ParamTySpec::new(Some(name.into_token()), t_spec_with_op.t_spec) + let param_spec = + ParamTySpec::new(Some(name.into_token()), t_spec_with_op.t_spec); + let default_spec = Self::expr_to_type_spec(param.default_val)?; + DefaultParamTySpec::new(param_spec, default_spec) } - (ParamPattern::VarName(name), None) => ParamTySpec::anonymous(TypeSpec::PreDeclTy( - PreDeclTypeSpec::Simple(SimpleTypeSpec::new(name, ConstArgs::empty())), - )), - _ => todo!(), + (ParamPattern::VarName(name), None) => { + let default_spec = Self::expr_to_type_spec(param.default_val)?; + let param_spec = + ParamTySpec::new(Some(name.into_token()), default_spec.clone()); + DefaultParamTySpec::new(param_spec, default_spec) + } + (l, r) => todo!("{:?} {:?}", l, r), }; defaults.push(param); }