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:
		
							parent
							
								
									18d2beeadb
								
							
						
					
					
						commit
						d7af418a63
					
				| 
						 | 
				
			
			@ -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#"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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, .. }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue