Skip to content

const generic inference variables not properly tracked by traits/fulfill. #70180

Closed

Description

@eddyb

I've come up with this example (playground):

#![feature(const_generics)]

fn works() {
    let array/*: [_; _]*/ = default_array();
    let _: [_; 4] = array;
    Foo::foo(&array);
}

fn doesnt_work() {
    let array/*: [_; _]*/ = default_array();
    // ^ cannot infer type for type parameter `T` declared on the function `default_array`
    Foo::foo(&array);
    let _: [_; 4] = array;
}

trait Foo {
    fn foo(&self) {}
}

impl Foo for [i32; 4] {}
impl Foo for [i64; 8] {}

// Only needed because `[_; _]` is not valid type syntax.
fn default_array<T, const N: usize>() -> [T; N]
    where [T; N]: Default,
{
    Default::default()
}

My understanding is that the error is caused by the [$T; $C]: Foo obligation being stalled_on on just $T (which means it's not retried when $C is unified with 4), whereas it should be stalled on both $T and $C so that it's retried when either changes.

Right now stalled_on is limited to type inference variables, so its representation will need to change, and Ty::walk will need to expose constants too.

I believe #70107 ran into this as well, but for WF obligations, not trait ones.

I'm self-assigning this because I'm working on the fix (as part of a larger effort).

cc @nikomatsakis @varkor @yodaldevoid

Activity

  1. self-assigned this
    on Mar 20, 2020
  2. added
    C-bugCategory: This is a bug.
    requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Mar 20, 2020
  3. eddyb commented on Mar 20, 2020

    @eddyb
    ContributorAuthor

    Note to self: the PR fixing this should also test this example (playground):

    #![feature(const_generics)]
    
    fn works() {
        let array/*: [u8; _]*/ = default_byte_array();
        let _: [_; 4] = array;
        Foo::foo(&array);
    }
    
    fn doesnt_work() {
        let array/*: [u8; _]*/ = default_byte_array();
        Foo::foo(&array);
        // ^ cannot infer type for type parameter `T` declared on the trait `Foo`
        let _: [_; 4] = array;
    }
    
    trait Foo<T> {
        fn foo(&self) {}
    }
    
    impl Foo<i32> for [u8; 4] {}
    impl Foo<i64> for [u8; 8] {}
    
    // Only needed because `[u8; _]` is not valid type syntax.
    fn default_byte_array<const N: usize>() -> [u8; N]
        where [u8; N]: Default,
    {
        Default::default()
    }

    The reason for this is that this second example has the type and const inference variables in different generic args of Foo, meaning fixing it also requires changing this to has_infer_types_or_consts:

    .filter(|t| t.has_infer_types())

  4. varkor commented on Mar 20, 2020

    @varkor
    Contributor

    I've definitely noticed problems with inference involving consts before, but wasn't able to pin down where the issue was stemming from. It would be great if this could be addressed once and for all.

  5. added 3 commits that reference this issue on Mar 24, 2020
  6. added 2 commits that reference this issue on May 25, 2020
    04daee2
    b3f1b95
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-const-genericsArea: const generics (parameters and arguments)A-inferenceArea: Type inferenceC-bugCategory: This is a bug.F-const_generics`#![feature(const_generics)]`T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.requires-nightlyThis issue requires a nightly compiler in some way. When possible, use a F-* label instead.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions