Skip to content

crates are considered for fn() -> type name resolution if they have generic parameters #139095

Open

Description

@jyn514

I tried this code:

extern crate libc as usize;
extern crate libc as Option;
#[usize::inner] //~ ERROR could not find `inner` in `usize`
fn foo() {}
fn bar() -> usize { 0 } // OK
fn baz() -> Option<T> { 0 } //~ ERROR type arguments not allowed on crate

I expected to see this happen: usize and Option should both consistently resolve to the crate, or they should consistently resolve to the builtin type.

Instead, this happened: In return position, usize resolves to the builtin type and Option resolves to the crate.
In attribute position, usize resolves to the crate (which seems reasonable, because associated macros aren't a thing.)

Meta

rustc --version --verbose: 1.87.0-nightly (2025-03-28 920d95eaf23d7eb6b415)

@rustbot label A-resolve

Activity

  1. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    A-resolveArea: Name/path resolution done by `rustc_resolve` specifically
    on Mar 29, 2025
  2. changed the title [-]crates are not considered for `fn() -> type` name resolution, except if they have generic parameters[/-] [+]crates are considered for `fn() -> type` name resolution if they have generic parameters[/+] on Mar 29, 2025
  3. jyn514 commented on Mar 29, 2025

    @jyn514
    MemberAuthor
  4. compiler-errors commented on Mar 30, 2025

    @compiler-errors
    Contributor

    I think this is two things entangled into what seems like one bug?

    Specifically, I don't think the preference for crates over types is because of the presence of generic args. I think we just prefer primitives over crate names in resolution.

    Specifically, we should be hitting a resolver error before even trying to compute the generics of Option<T> when Option is defined as a crate name:

    error[E0573]: expected type, found crate `Option`
     --> src/lib.rs:6:13
      |
    6 | fn baz() -> Option<T> { 0 }
      |             ^^^^^^^^^ not a type
    

    Am I missing something, b/c I can't seem to reproduce the error "type arguments not allowed on crate" with the code you shared?

    I'm reading between the lines, but did you happen to modify this example to use Option when filing this bug, but previously were experimenting with something like the following code?

    extern crate libc as usize;
    
    extern crate libc as isize;
    
    fn bar() -> usize { 0 } // OK
    
    fn baz() -> isize<i32> { 0 } // type arguments are not allowed on crate `libc`

    According to that error, it may look like baz's return type is resolving to libc as isize, but I think that's just a diagnostic bug, since we later go on to note:

    help: primitive type `isize` doesn't have generic parameters
      |
    4 - fn baz() -> isize<i32> { 0 } //~ ERROR type arguments not allowed on crate
    4 + fn baz() -> isize { 0 } //~ ERROR type arguments not allowed on crate
    

    And indeed, the "path res" (the resolution) for the full path isize<i32> is indeed PrimTy, even if the "segment res" (resolution of just the path segment) is the crate. That's probably just a bug.

  5. compiler-errors commented on Mar 30, 2025

    @compiler-errors
    Contributor

    // In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we
    // don't report an error right away, but try to fallback to a primitive type.
    // So, we are still able to successfully resolve something like
    //
    // use std::u8; // bring module u8 in scope
    // fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8
    // u8::max_value() // OK, resolves to associated function <u8>::max_value,
    // // not to nonexistent std::u8::max_value
    // }
    //
    // Such behavior is required for backward compatibility.
    // The same fallback is used when `a` resolves to nothing.
    PathResult::Module(ModuleOrUniformRoot::Module(_)) | PathResult::Failed { .. }
    if (ns == TypeNS || path.len() > 1)
    && PrimTy::from_name(path[0].ident.name).is_some() =>
    {
    let prim = PrimTy::from_name(path[0].ident.name).unwrap();
    let tcx = self.r.tcx();
    let gate_err_sym_msg = match prim {
    PrimTy::Float(FloatTy::F16) if !tcx.features().f16() => {
    Some((sym::f16, "the type `f16` is unstable"))
    }
    PrimTy::Float(FloatTy::F128) if !tcx.features().f128() => {
    Some((sym::f128, "the type `f128` is unstable"))
    }
    _ => None,
    };
    if let Some((sym, msg)) = gate_err_sym_msg {
    let span = path[0].ident.span;
    if !span.allows_unstable(sym) {
    feature_err(tcx.sess, sym, span, msg).emit();
    }
    };
    PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1)
    }

    This is why we prefer primitives > crate resolutions. So I don't think this has to do with the presence of generic parameters, and that wonky generic parameter error message that mentions "type arguments are not allowed on crate" which I shared above which is just a diagnostics bug which I've fixed in #139127.

    LMK if I'm missing something critical here

  6. jyn514 commented on Mar 30, 2025

    @jyn514
    MemberAuthor

    I'm reading between the lines, but did you happen to modify this example to use Option when filing this bug, but previously were experimenting with something like the following code?

    you're absolutely right, that comment is left over from an old version of the code. nice catch, thanks.

  7. added a commit that references this issue on Apr 14, 2025
  8. added a commit that references this issue on Apr 14, 2025
  9. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    and removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on May 1, 2025
  10. bb1yd commented on Jul 17, 2026

    @bb1yd
    Contributor

    Should we close this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-resolveArea: Name/path resolution done by `rustc_resolve` specificallyC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions