Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC 213: Implement Default Type Parameter Fallback #26870

Merged
merged 18 commits into from
Jul 26, 2015

Conversation

jroesch
Copy link
Member

@jroesch jroesch commented Jul 7, 2015

This PR completes RFC 213 by allowing default type parameters to influence inference. This is almost certainly a breaking change due to interactions between default type parameters and the old fallback algorithm used for integral and floating point literals.

The error messages still require polish but I wanted to get early review and feedback from others on the the changes, error messages, and test cases. I also imagine we will want to run anywhere from 1-3 versions of this on crater and evaluate the impact, and it would be best to get that ball rolling.

The only outstanding issue I'm aware of is that type alias defaults don't work. It seems this may require significant restructuring, since during inference type aliases have already been expanded. @nikomatsakis might be able to provide some clarity here.

r? @nikomatsakis

cc @eddyb @gankro @aturon @brson

@aturon
Copy link
Member

aturon commented Jul 7, 2015

\o/


// Here, B is instantiated with $1=uint, and constraint $0 <: $1 is added.
bar(x);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error message?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was working on improving it this afternoon/evening but got side tracked by trying to get type aliases to work correctly. Going to try to finish (and then add it here) it tomorrow morning PST.

@bluss
Copy link
Member

bluss commented Jul 8, 2015

Is it a breaking change for code involving default type parameters in struct declarations? I guess not. Defaults in impl blocks? Defaults in methods and functions' type parameters? (Yes, I guess it must be).

The rationale is that type parameter defaults never did anything really for methods and functions, so it's not breaking a previously working feature(?)

@bluss
Copy link
Member

bluss commented Jul 8, 2015

Default type parameters allow a form of static function parameters with defaults. Imagine fn graphemes<Kind: GraphemeKind = Extended>(&self) and then you can call it as .graphemes::<Legacy>() or just .graphemes() to get the default.

@Gankra
Copy link
Contributor

Gankra commented Jul 8, 2015

Definitely would like a crater build of this change just to see what the impact would be. I don't expect much breakage in practice.

@@ -98,6 +98,9 @@ pub struct InferCtxt<'a, 'tcx: 'a> {
normalize: bool,

err_count_on_creation: usize,

// Default Type Parameter fallbacks
pub defaults: RefCell<FnvHashMap<Ty<'tcx>, Ty<'tcx>>>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I'm concerned about this map.

For one thing, I'd want to "encapsulate it more":

a. make this private
b. key it by ty::TyVid
c. insert new data by adding an (optional) parameter to next_ty_var, rather than mutating the table after the fact

But a bigger issue is that it should be versioned for transactions. As it is, we are going to create fresh type variables with defaults then (potentially) roll them back, which might clear the default. I think my preference would be to remove the map, and instead store the Option<Ty<'tcx>> as part of the Bounded variant in type_variable::TypeVariableValue (after all, who cares what the default was once the type is Known?)

I'd probably change TypeVariableValue to something like:

enum TypeVariableValue<'tcx> {
    Known(Ty<'tcx>),
    Bounded { relations: Vec<Relation>, default: Option<Ty<'tcx>> }
}

(Also, if you do it this way, the transactional problem should just take care of itself.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did this refactor, testing now.

@nikomatsakis
Copy link
Contributor

More tests that would be nice:

  • Test that i32 and () fallback takes precedence.
  • Tests where the defaults reference once another.
  • Try to pin @gankro down and have him give you one of the collections patterns he would like to see working.

@Gankra
Copy link
Contributor

Gankra commented Jul 8, 2015

CC @apasel422 and @reem for crazy uses of defaults

@bors
Copy link
Contributor

bors commented Jul 12, 2015

☔ The latest upstream changes (presumably #26895) made this pull request unmergeable. Please resolve the merge conflicts.

}
});
//.subst(self.tcx, &substs)
let ty_var = self.next_ty_var_with_default(default);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we still are not substituting here, right? I am guessing you'll have problems related to references to other variables, as well as maybe Self...?

@brson
Copy link
Contributor

brson commented Jul 20, 2015

Crater says: https://gist.github.com/brson/ce88d850e673ea2c2d05

Two stack overflows.

@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Jul 26, 2015

📌 Commit 5ad36cb has been approved by nikomatsakis

bors added a commit that referenced this pull request Jul 26, 2015
This PR completes [RFC 213](https://github.com/rust-lang/rfcs/blob/master/text/0213-defaulted-type-params.md) by allowing default type parameters to influence inference. This is almost certainly a breaking change due to interactions between default type parameters and the old fallback algorithm used for integral and floating point literals.

The error messages still require polish but I wanted to get early review and feedback from others on the the changes, error messages, and test cases. I also imagine we will want to run anywhere from 1-3 versions of this on crater and evaluate the impact, and it would be best to get that ball rolling. 

The only outstanding issue I'm aware of is that type alias defaults don't work. It seems this may require significant restructuring, since during inference type aliases have already been expanded. @nikomatsakis might be able to provide some clarity here.

r? @nikomatsakis 

cc @eddyb @gankro @aturon @brson
@bors
Copy link
Contributor

bors commented Jul 26, 2015

⌛ Testing commit 5ad36cb with merge a5c12f4...

@petrochenkov
Copy link
Contributor

Hm, after this change I still can't implement heterogeneous comparisons for Option without breakage.

Reduced case:

// Almost PartialEq
trait PartialQe<Rhs = Self> {
    fn qe(&self, other: &Rhs) {}
}

impl<A, B> PartialQe<Option<B>> for Option<A> {}

fn main() {
    // `None` is not inferred to be `None::<&str>` based on the default `Rhs = Self`
    PartialQe::qe(&Some("str"), &None); // error: unable to infer enough type information about `_`; type annotations or generic parameter binding required [E0282]
}

@eddyb
Copy link
Member

eddyb commented Jul 26, 2015

@petrochenkov Maybe the impl also needs the default?

@petrochenkov
Copy link
Contributor

@eddyb
impl<A, B = A> PartialQe<Option<B>> for Option<A> {} or impl<B, A = B> PartialQe<Option<B>> for Option<A> {} don't seem to work either.

@Gankra
Copy link
Contributor

Gankra commented Jul 26, 2015

💓 😻 😍 💖 ✨

@jroesch
Copy link
Member Author

jroesch commented Jul 26, 2015

This program works on the compiler built from my branch:

// Almost PartialEq
trait PartialQe<Rhs = Self> {
        fn qe(&self, other: &Rhs) {}
}

impl<A, B = A> PartialQe<Option<B>> for Option<A> {}

fn main() {
        PartialQe::qe(&Some("str"), &None); 
        Some('a').qe(&None);
}

@petrochenkov
Copy link
Contributor

Now I see, it works only when the feature gate is enabled.

#![feature(default_type_parameter_fallback)]

So, it can't yet be used to generalize standard library facilities, like Option, because users on stable won't be able to unbreak their code by enabling the feature gate.

@jroesch
Copy link
Member Author

jroesch commented Jul 27, 2015

@petrochenkov we are going to let it bake for a cycle in order to give us time to tweak the algorithm, then it will be stabilized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.