Skip to content

Commit ea2b4a7

Browse files
committed
add support for generic parameter defaults
1 parent 078b234 commit ea2b4a7

28 files changed

+785
-113
lines changed

crates/hir-analysis/src/diagnostics.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,25 +1010,24 @@ impl DiagnosticVoucher for TyLowerDiag<'_> {
10101010
}
10111011
}
10121012

1013-
Self::DuplicateGenericParamName(adt, idxs) => {
1014-
let message = if let Some(name) = adt.name(db) {
1013+
Self::DuplicateGenericParamName(owner, idxs) => {
1014+
let message = if let Some(name) = owner.name(db) {
10151015
format!(
10161016
"duplicate generic parameter name in {} `{}`",
1017-
adt.kind_name(),
1017+
owner.kind_name(),
10181018
name.data(db)
10191019
)
10201020
} else {
10211021
format!(
10221022
"duplicate generic parameter name in {} definition",
1023-
adt.kind_name()
1023+
owner.kind_name()
10241024
)
10251025
};
10261026

1027-
let gen = adt.generic_owner().unwrap();
1028-
let name = gen.params(db).data(db)[0].name().unwrap().data(db);
1027+
let name = owner.params(db).data(db)[0].name().unwrap().data(db);
10291028
let spans = idxs
10301029
.iter()
1031-
.map(|i| gen.params_span().param(*i as usize).resolve(db));
1030+
.map(|i| owner.params_span().param(*i as usize).resolve(db));
10321031
CompleteDiagnostic {
10331032
severity: Severity::Error,
10341033
message,
@@ -1124,6 +1123,30 @@ impl DiagnosticVoucher for TyLowerDiag<'_> {
11241123
notes: vec![],
11251124
error_code,
11261125
},
1126+
1127+
Self::NonTrailingDefaultGenericParam(span) => CompleteDiagnostic {
1128+
severity: Severity::Error,
1129+
message: "generic parameters with a default must be trailing".to_string(),
1130+
sub_diagnostics: vec![SubDiagnostic {
1131+
style: LabelStyle::Primary,
1132+
message: "must not be followed by a parameter with no default".to_string(),
1133+
span: span.resolve(db),
1134+
}],
1135+
notes: vec![],
1136+
error_code,
1137+
},
1138+
1139+
Self::GenericDefaultForwardRef { span, name } => CompleteDiagnostic {
1140+
severity: Severity::Error,
1141+
message: "cannot reference generic parameter before it is declared".to_string(),
1142+
sub_diagnostics: vec![SubDiagnostic {
1143+
style: LabelStyle::Primary,
1144+
message: format!("cannot reference `{}` before it's declared", name.data(db)),
1145+
span: span.resolve(db),
1146+
}],
1147+
notes: vec![],
1148+
error_code,
1149+
},
11271150
}
11281151
}
11291152
}

crates/hir-analysis/src/name_resolution/path_resolver.rs

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,7 @@ pub fn resolve_name_res<'db>(
884884
ScopeId::Item(item) => match item {
885885
ItemKind::Struct(_) | ItemKind::Contract(_) | ItemKind::Enum(_) => {
886886
let adt_ref = AdtRef::try_from_item(item).unwrap();
887-
PathRes::Ty(ty_from_adtref(db, path, adt_ref, args)?)
887+
PathRes::Ty(ty_from_adtref(db, path, adt_ref, args, assumptions)?)
888888
}
889889

890890
ItemKind::TopMod(_) | ItemKind::Mod(_) => PathRes::Mod(scope_id),
@@ -915,18 +915,7 @@ pub fn resolve_name_res<'db>(
915915
ItemKind::TypeAlias(type_alias) => {
916916
let alias = lower_type_alias(db, type_alias);
917917
let expected = alias.params(db).len();
918-
if args.len() < expected {
919-
PathRes::TyAlias(
920-
alias.clone(),
921-
TyId::invalid(
922-
db,
923-
InvalidCause::UnboundTypeAliasParam {
924-
alias: type_alias,
925-
n_given_args: args.len(),
926-
},
927-
),
928-
)
929-
} else if args.len() > expected {
918+
if args.len() > expected {
930919
return Err(PathResError::new(
931920
PathResErrorKind::ArgNumMismatch {
932921
expected,
@@ -935,7 +924,26 @@ pub fn resolve_name_res<'db>(
935924
path,
936925
));
937926
} else {
938-
let instantiated = alias.alias_to.instantiate(db, args);
927+
let completed = alias.param_set.complete_explicit_args_with_defaults(
928+
db,
929+
None,
930+
args,
931+
assumptions,
932+
);
933+
if completed.len() < expected {
934+
return Ok(PathRes::TyAlias(
935+
alias.clone(),
936+
TyId::invalid(
937+
db,
938+
InvalidCause::UnboundTypeAliasParam {
939+
alias: type_alias,
940+
n_given_args: args.len(),
941+
},
942+
),
943+
));
944+
}
945+
946+
let instantiated = alias.alias_to.instantiate(db, &completed);
939947
if let TyData::Invalid(InvalidCause::TooManyGenericArgs {
940948
expected,
941949
given,
@@ -1035,7 +1043,7 @@ pub fn resolve_name_res<'db>(
10351043
} else {
10361044
// The variant was imported via `use`.
10371045
debug_assert!(path.parent(db).is_none());
1038-
ty_from_adtref(db, path, var.enum_.into(), &[])?
1046+
ty_from_adtref(db, path, var.enum_.into(), &[], assumptions)?
10391047
};
10401048
// TODO report error if args isn't empty
10411049
PathRes::EnumVariant(ResolvedVariant {
@@ -1073,10 +1081,15 @@ fn ty_from_adtref<'db>(
10731081
path: PathId<'db>,
10741082
adt_ref: AdtRef<'db>,
10751083
args: &[TyId<'db>],
1084+
assumptions: PredicateListId<'db>,
10761085
) -> PathResolutionResult<'db, TyId<'db>> {
10771086
let adt = lower_adt(db, adt_ref);
10781087
let ty = TyId::adt(db, adt);
1079-
let applied = TyId::foldl(db, ty, args);
1088+
// Fill trailing defaults (if any)
1089+
let completed_args =
1090+
adt.param_set(db)
1091+
.complete_explicit_args_with_defaults(db, None, args, assumptions);
1092+
let applied = TyId::foldl(db, ty, &completed_args);
10801093
if let TyData::Invalid(InvalidCause::TooManyGenericArgs { expected, given }) = applied.data(db)
10811094
{
10821095
Err(PathResError::new(

0 commit comments

Comments
 (0)