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]
fn forbid_importing_or_using_opaque_constructors() {
let dependency = r#"

View File

@ -1079,7 +1079,7 @@ The best thing to do from here is to remove it."#))]
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(help(
"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>,
},
#[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(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."
@ -1104,6 +1104,16 @@ The best thing to do from here is to remove it."#))]
#[label("redundant fallback handler")]
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 {
@ -1166,7 +1176,8 @@ impl ExtraData for Error {
| Error::UnknownValidatorHandler { .. }
| Error::UnexpectedValidatorFallback { .. }
| Error::IncorrectBenchmarkArity { .. }
| Error::MustInferFirst { .. } => None,
| Error::MustInferFirst { .. }
| Error::InvalidFieldAccess { .. } => None,
Error::UnknownType { name, .. }
| Error::UnknownTypeConstructor { name, .. }

View File

@ -1095,6 +1095,12 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
location: module_location,
} = 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
// 'as'), to obtain its _full unambiguous name_.
let (_, module) = self