refactor generic#1081
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
|
/gemini review |
现在 std.Unpack 的目标泛型必须使用 std.ConstTpl 包裹以保持常量传播
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive overhaul of the generic inference system, transitioning to a constraint-based model that supports co- and contravariant variance and improves the handling of structural literals. Key additions include the implementation of Pick and Omit utility types, a pre-analysis phase for nested table fields in function arguments, and a refactored type instantiation logic to better manage recursive aliases. Review feedback identifies several necessary refinements to the new inference engine: resolve_unpack_operands should be updated to fully expand variadic parameters, the __pairs metamethod logic needs to correctly unpack the return tuple to isolate the iterator function, and support for MultiLineUnion and ConstTplRef should be added to is_literal_candidate and variadic inference branches, respectively, to ensure type consistency.
| SubstitutorValue::Params(params) => Some( | ||
| params | ||
| .first() | ||
| .unwrap_or(&(String::new(), None)) | ||
| .1 | ||
| .clone() | ||
| .unwrap_or(LuaType::Unknown), | ||
| ), |
There was a problem hiding this comment.
The current implementation for SubstitutorValue::Params in resolve_unpack_operands only takes the first parameter from the variadic list, which causes information loss when unpacking a variadic template. It should expand all parameters into a VariadicType::Multi to correctly support multi-return values from variadic generics.
| SubstitutorValue::Params(params) => Some( | |
| params | |
| .first() | |
| .unwrap_or(&(String::new(), None)) | |
| .1 | |
| .clone() | |
| .unwrap_or(LuaType::Unknown), | |
| ), | |
| SubstitutorValue::Params(params) => Some(LuaType::Variadic( | |
| VariadicType::Multi( | |
| params | |
| .iter() | |
| .map(|(_, ty)| ty.clone().unwrap_or(LuaType::Unknown)) | |
| .collect(), | |
| ) | |
| .into(), | |
| )), |
| let final_return_type = match meta_return { | ||
| LuaType::DocFunction(doc_func) => Some(doc_func.get_ret().clone()), | ||
| LuaType::Signature(signature_id) => context | ||
| .db | ||
| .get_signature_index() | ||
| .get(&signature_id) | ||
| .map(|signature| signature.get_return_type()), | ||
| _ => None, | ||
| }; |
There was a problem hiding this comment.
The logic for handling __pairs metamethod return types is incomplete. __pairs typically returns a tuple (iterator, state, initial_value). The current code tries to match the entire return tuple against DocFunction or Signature, which will fail if it's a multi-return. It should first extract the iterator function (the first slot of the return) before attempting to get its return type.
let iterator_func = meta_return.get_result_slot_type(0).unwrap_or(meta_return);
let final_return_type = match iterator_func {
LuaType::DocFunction(doc_func) => Some(doc_func.get_ret().clone()),
LuaType::Signature(signature_id) => context.db.get_signature_index()
.get(&signature_id)
.map(|signature| signature.get_return_type()),
_ => None,
};| pub(in crate::semantic::generic) fn is_literal_candidate(ty: &LuaType) -> bool { | ||
| match ty { | ||
| LuaType::StringConst(_) | ||
| | LuaType::DocStringConst(_) | ||
| | LuaType::IntegerConst(_) | ||
| | LuaType::DocIntegerConst(_) | ||
| | LuaType::FloatConst(_) | ||
| | LuaType::BooleanConst(_) | ||
| | LuaType::DocBooleanConst(_) | ||
| | LuaType::TableConst(_) => true, | ||
| LuaType::Union(union) => union.into_vec().iter().any(is_literal_candidate), | ||
| LuaType::Tuple(tuple) => tuple.get_types().iter().any(is_literal_candidate), | ||
| LuaType::Variadic(variadic) => match variadic.deref() { | ||
| VariadicType::Base(base) => is_literal_candidate(base), | ||
| VariadicType::Multi(types) => types.iter().any(is_literal_candidate), | ||
| }, | ||
| _ => false, | ||
| } | ||
| } |
There was a problem hiding this comment.
is_literal_candidate is missing handling for LuaType::MultiLineUnion. This might cause literal preservation logic to fail for templates inferred from multi-line unions.
pub(in crate::semantic::generic) fn is_literal_candidate(ty: &LuaType) -> bool {
match ty {
LuaType::StringConst(_)
| LuaType::DocStringConst(_)
| LuaType::IntegerConst(_)
| LuaType::DocIntegerConst(_)
| LuaType::FloatConst(_)
| LuaType::BooleanConst(_)
| LuaType::DocBooleanConst(_)
| LuaType::TableConst(_) => true,
LuaType::Union(union) => union.into_vec().iter().any(is_literal_candidate),
LuaType::MultiLineUnion(multi) => multi
.get_unions()
.iter()
.any(|(ty, _)| is_literal_candidate(ty)),
LuaType::Tuple(tuple) => tuple.get_types().iter().any(is_literal_candidate),
LuaType::Variadic(variadic) => match variadic.deref() {
VariadicType::Base(base) => is_literal_candidate(base),
VariadicType::Multi(types) => types.iter().any(is_literal_candidate),
},
_ => false,
}
}| if let LuaType::TplRef(tpl_ref) = source_base { | ||
| context.insert_type( | ||
| tpl_ref.get_tpl_id(), | ||
| InferenceCandidate::ordinary(target_base.clone()), | ||
| variance, | ||
| false, | ||
| priority, | ||
| ); | ||
| } |
There was a problem hiding this comment.
This variadic inference branch only handles TplRef, but it should also support ConstTplRef to ensure that constant templates are correctly inferred when used as variadic bases. Similar omissions exist in other variadic inference helpers in this file (e.g., function_varargs_infer_types and tuple_infer_types).
No description provided.