return dedicated error on invalid type field access, instead of confusing 'unknown module.'

Signed-off-by: KtorZ <matthias.benkort@gmail.com>
This commit is contained in:
KtorZ 2025-03-16 00:45:20 +01:00
parent 18d2beeadb
commit d7af418a63
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
3 changed files with 78 additions and 3 deletions

View File

@ -2724,6 +2724,64 @@ fn use_non_imported_module_as_namespace() {
); );
} }
#[test]
fn invalid_type_field_access_chain() {
let dependency = r#"
pub type Foo {
I(Int)
B(Bool)
}
"#;
let source_code = r#"
use foo.{Foo}
test my_test() {
trace Foo.I.Int(42)
Void
}
"#;
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
assert!(
matches!(
&result,
Err((warnings, Error::InvalidFieldAccess { .. })) if warnings.is_empty(),
),
"{result:#?}"
);
}
#[test]
fn invalid_type_field_access_chain_2() {
let dependency = r#"
pub type Foo {
I(Int)
B(Bool)
}
"#;
let source_code = r#"
use foo.{Foo}
test my_test() {
trace Foo.i(42)
Void
}
"#;
let result = check_with_deps(parse(source_code), vec![(parse_as(dependency, "foo"))]);
assert!(
matches!(
&result,
Err((warnings, Error::UnknownTypeConstructor { .. })) if warnings.is_empty(),
),
"{result:#?}"
);
}
#[test] #[test]
fn forbid_importing_or_using_opaque_constructors() { fn forbid_importing_or_using_opaque_constructors() {
let dependency = r#" let dependency = r#"

View File

@ -1079,7 +1079,7 @@ The best thing to do from here is to remove it."#))]
available_purposes: Vec<String>, available_purposes: Vec<String>,
}, },
#[error("I could not find an appropriate handler in the validator definition\n")] #[error("I could not find an appropriate handler in the validator definition.\n")]
#[diagnostic(code("unknown::handler"))] #[diagnostic(code("unknown::handler"))]
#[diagnostic(help( #[diagnostic(help(
"When referring to a validator handler via record access, you must refer to one of the declared handlers{}{}", "When referring to a validator handler via record access, you must refer to one of the declared handlers{}{}",
@ -1095,7 +1095,7 @@ The best thing to do from here is to remove it."#))]
available_handlers: Vec<String>, available_handlers: Vec<String>,
}, },
#[error("I caught an extraneous fallback handler in an already exhaustive validator\n")] #[error("I caught an extraneous fallback handler in an already exhaustive validator.\n")]
#[diagnostic(code("extraneous::fallback"))] #[diagnostic(code("extraneous::fallback"))]
#[diagnostic(help( #[diagnostic(help(
"Validator handlers must be exhaustive and either cover all purposes, or provide a fallback handler. Here, you have successfully covered all script purposes with your handler, but left an extraneous fallback branch. I cannot let that happen, but removing it for you would probably be deemed rude. So please, remove the fallback." "Validator handlers must be exhaustive and either cover all purposes, or provide a fallback handler. Here, you have successfully covered all script purposes with your handler, but left an extraneous fallback branch. I cannot let that happen, but removing it for you would probably be deemed rude. So please, remove the fallback."
@ -1104,6 +1104,16 @@ The best thing to do from here is to remove it."#))]
#[label("redundant fallback handler")] #[label("redundant fallback handler")]
fallback: Span, fallback: Span,
}, },
#[error("I was stopped by a suspicious field access chain.\n")]
#[diagnostic(code("invalid::field_access"))]
#[diagnostic(help(
"It seems like you've got things mixed up a little here? You can only access fields exported by modules or, by types within those modules. Double-check the culprit field access chain, there's likely something wrong about it."
))]
InvalidFieldAccess {
#[label("invalid field access")]
location: Span,
},
} }
impl ExtraData for Error { impl ExtraData for Error {
@ -1166,7 +1176,8 @@ impl ExtraData for Error {
| Error::UnknownValidatorHandler { .. } | Error::UnknownValidatorHandler { .. }
| Error::UnexpectedValidatorFallback { .. } | Error::UnexpectedValidatorFallback { .. }
| Error::IncorrectBenchmarkArity { .. } | Error::IncorrectBenchmarkArity { .. }
| Error::MustInferFirst { .. } => None, | Error::MustInferFirst { .. }
| Error::InvalidFieldAccess { .. } => None,
Error::UnknownType { name, .. } Error::UnknownType { name, .. }
| Error::UnknownTypeConstructor { name, .. } | Error::UnknownTypeConstructor { name, .. }

View File

@ -1095,6 +1095,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
location: module_location, location: module_location,
} = type_container.as_ref() } = type_container.as_ref()
{ {
if TypeConstructor::might_be(module_name) {
return Err(Error::InvalidFieldAccess {
location: access_location,
});
}
// Lookup the module using the declared name (which may have been rebind with // Lookup the module using the declared name (which may have been rebind with
// 'as'), to obtain its _full unambiguous name_. // 'as'), to obtain its _full unambiguous name_.
let (_, module) = self let (_, module) = self