Skip to content

Commit

Permalink
⬆️ rust-analyzer
Browse files Browse the repository at this point in the history
  • Loading branch information
lnicola committed Nov 9, 2022
1 parent c60b1f6 commit 79923c3
Show file tree
Hide file tree
Showing 74 changed files with 1,216 additions and 422 deletions.
3 changes: 1 addition & 2 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ Forum for questions: https://users.rust-lang.org/c/ide/14
Before submitting, please make sure that you're not running into one of these known issues:
1. extension doesn't load in VSCodium: #11080
2. on-the-fly diagnostics are mostly unimplemented (`cargo check` diagnostics will be shown when saving a file): #3107
1. on-the-fly diagnostics are mostly unimplemented (`cargo check` diagnostics will be shown when saving a file): #3107
Otherwise please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3.
-->
Expand Down
5 changes: 2 additions & 3 deletions .github/ISSUE_TEMPLATE/critical_nightly_regression.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
name: Critical Nightly Regression
about: You are using nightly rust-analyzer and the latest version is unusable.
title: ''
labels: ''
assignees: 'matklad'
labels: 'Broken Window'
assignees: ''

---

Expand All @@ -14,4 +14,3 @@ Please try to provide information which will help us to fix the issue faster. Mi
-->

This is a serious regression in nightly and it's important to fix it before the next release.
@matklad, please take a look.
5 changes: 2 additions & 3 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,7 @@ jobs:
- name: Publish Extension (OpenVSX, release)
if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
working-directory: ./editors/code
# token from https://dev.azure.com/rust-analyzer/
run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
timeout-minutes: 2

- name: Publish Extension (Code Marketplace, nightly)
Expand All @@ -269,5 +268,5 @@ jobs:
- name: Publish Extension (OpenVSX, nightly)
if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
working-directory: ./editors/code
run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true
run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
timeout-minutes: 2
5 changes: 4 additions & 1 deletion crates/hir-def/src/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,12 @@ pub(crate) fn print_type_ref(type_ref: &TypeRef, buf: &mut dyn Write) -> fmt::Re
print_type_ref(elem, buf)?;
write!(buf, "]")?;
}
TypeRef::Fn(args_and_ret, varargs) => {
TypeRef::Fn(args_and_ret, varargs, is_unsafe) => {
let ((_, return_type), args) =
args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
if *is_unsafe {
write!(buf, "unsafe ")?;
}
write!(buf, "fn(")?;
for (i, (_, typeref)) in args.iter().enumerate() {
if i != 0 {
Expand Down
6 changes: 3 additions & 3 deletions crates/hir-def/src/type_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub enum TypeRef {
Array(Box<TypeRef>, ConstScalarOrPath),
Slice(Box<TypeRef>),
/// A fn pointer. Last element of the vector is the return type.
Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/),
Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/, bool /*is_unsafe*/),
ImplTrait(Vec<Interned<TypeBound>>),
DynTrait(Vec<Interned<TypeBound>>),
Macro(AstId<ast::MacroCall>),
Expand Down Expand Up @@ -229,7 +229,7 @@ impl TypeRef {
Vec::new()
};
params.push((None, ret_ty));
TypeRef::Fn(params, is_varargs)
TypeRef::Fn(params, is_varargs, inner.unsafe_token().is_some())
}
// for types are close enough for our purposes to the inner type for now...
ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
Expand Down Expand Up @@ -263,7 +263,7 @@ impl TypeRef {
fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
f(type_ref);
match type_ref {
TypeRef::Fn(params, _) => {
TypeRef::Fn(params, _, _) => {
params.iter().for_each(|(_, param_type)| go(param_type, f))
}
TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)),
Expand Down
7 changes: 5 additions & 2 deletions crates/hir-ty/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1187,8 +1187,11 @@ impl HirDisplay for TypeRef {
inner.hir_fmt(f)?;
write!(f, "]")?;
}
TypeRef::Fn(parameters, is_varargs) => {
&TypeRef::Fn(ref parameters, is_varargs, is_unsafe) => {
// FIXME: Function pointer qualifiers.
if is_unsafe {
write!(f, "unsafe ")?;
}
write!(f, "fn(")?;
if let Some(((_, return_type), function_parameters)) = parameters.split_last() {
for index in 0..function_parameters.len() {
Expand All @@ -1203,7 +1206,7 @@ impl HirDisplay for TypeRef {
write!(f, ", ")?;
}
}
if *is_varargs {
if is_varargs {
write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?;
}
write!(f, ")")?;
Expand Down
2 changes: 1 addition & 1 deletion crates/hir-ty/src/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,7 @@ impl Expectation {
/// The primary use case is where the expected type is a fat pointer,
/// like `&[isize]`. For example, consider the following statement:
///
/// let x: &[isize] = &[1, 2, 3];
/// let x: &[isize] = &[1, 2, 3];
///
/// In this case, the expected type for the `&[1, 2, 3]` expression is
/// `&[isize]`. If however we were to say that `[1, 2, 3]` has the
Expand Down
1 change: 1 addition & 0 deletions crates/hir-ty/src/infer/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ impl<'a> InferenceContext<'a> {
let ty = match &self.body[tgt_expr] {
Expr::Missing => self.err_ty(),
&Expr::If { condition, then_branch, else_branch } => {
let expected = &expected.adjust_for_branches(&mut self.table);
self.infer_expr(
condition,
&Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)),
Expand Down
88 changes: 83 additions & 5 deletions crates/hir-ty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@ use std::sync::Arc;
use chalk_ir::{
fold::{Shift, TypeFoldable},
interner::HasInterner,
NoSolution,
NoSolution, UniverseIndex,
};
use hir_def::{expr::ExprId, type_ref::Rawness, TypeOrConstParamId};
use hir_expand::name;
use itertools::Either;
use traits::FnTrait;
use utils::Generics;

use crate::{consteval::unknown_const, db::HirDatabase, utils::generics};
Expand Down Expand Up @@ -208,6 +210,7 @@ pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
pub struct CallableSig {
params_and_return: Arc<[Ty]>,
is_varargs: bool,
safety: Safety,
}

has_interner!(CallableSig);
Expand All @@ -216,9 +219,14 @@ has_interner!(CallableSig);
pub type PolyFnSig = Binders<CallableSig>;

impl CallableSig {
pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> CallableSig {
pub fn from_params_and_return(
mut params: Vec<Ty>,
ret: Ty,
is_varargs: bool,
safety: Safety,
) -> CallableSig {
params.push(ret);
CallableSig { params_and_return: params.into(), is_varargs }
CallableSig { params_and_return: params.into(), is_varargs, safety }
}

pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
Expand All @@ -235,13 +243,14 @@ impl CallableSig {
.map(|arg| arg.assert_ty_ref(Interner).clone())
.collect(),
is_varargs: fn_ptr.sig.variadic,
safety: fn_ptr.sig.safety,
}
}

pub fn to_fn_ptr(&self) -> FnPointer {
FnPointer {
num_binders: 0,
sig: FnSig { abi: (), safety: Safety::Safe, variadic: self.is_varargs },
sig: FnSig { abi: (), safety: self.safety, variadic: self.is_varargs },
substitution: FnSubst(Substitution::from_iter(
Interner,
self.params_and_return.iter().cloned(),
Expand All @@ -266,7 +275,11 @@ impl TypeFoldable<Interner> for CallableSig {
) -> Result<Self, E> {
let vec = self.params_and_return.to_vec();
let folded = vec.try_fold_with(folder, outer_binder)?;
Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
Ok(CallableSig {
params_and_return: folded.into(),
is_varargs: self.is_varargs,
safety: self.safety,
})
}
}

Expand Down Expand Up @@ -508,3 +521,68 @@ where
});
Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
}

pub fn callable_sig_from_fnonce(
self_ty: &Canonical<Ty>,
env: Arc<TraitEnvironment>,
db: &dyn HirDatabase,
) -> Option<CallableSig> {
let krate = env.krate;
let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;

let mut kinds = self_ty.binders.interned().to_vec();
let b = TyBuilder::trait_ref(db, fn_once_trait);
if b.remaining() != 2 {
return None;
}
let fn_once = b
.push(self_ty.value.clone())
.fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
.build();
kinds.extend(fn_once.substitution.iter(Interner).skip(1).map(|x| {
let vk = match x.data(Interner) {
chalk_ir::GenericArgData::Ty(_) => {
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
}
chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
chalk_ir::GenericArgData::Const(c) => {
chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
}
};
chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
}));

// FIXME: chalk refuses to solve `<Self as FnOnce<^0.0>>::Output == ^0.1`, so we first solve
// `<Self as FnOnce<^0.0>>` and then replace `^0.0` with the concrete argument tuple.
let trait_env = env.env.clone();
let obligation = InEnvironment { goal: fn_once.cast(Interner), environment: trait_env };
let canonical =
Canonical { binders: CanonicalVarKinds::from_iter(Interner, kinds), value: obligation };
let subst = match db.trait_solve(krate, canonical) {
Some(Solution::Unique(vars)) => vars.value.subst,
_ => return None,
};
let args = subst.at(Interner, self_ty.binders.interned().len()).ty(Interner)?;
let params = match args.kind(Interner) {
chalk_ir::TyKind::Tuple(_, subst) => {
subst.iter(Interner).filter_map(|arg| arg.ty(Interner).cloned()).collect::<Vec<_>>()
}
_ => return None,
};
if params.iter().any(|ty| ty.is_unknown()) {
return None;
}

let fn_once = TyBuilder::trait_ref(db, fn_once_trait)
.push(self_ty.value.clone())
.push(args.clone())
.build();
let projection =
TyBuilder::assoc_type_projection(db, output_assoc_type, Some(fn_once.substitution.clone()))
.build();

let ret_ty = db.normalize_projection(projection, env);

Some(CallableSig::from_params_and_return(params, ret_ty.clone(), false, Safety::Safe))
}
19 changes: 14 additions & 5 deletions crates/hir-ty/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,17 @@ impl<'a> TyLoweringContext<'a> {
.intern(Interner)
}
TypeRef::Placeholder => TyKind::Error.intern(Interner),
TypeRef::Fn(params, is_varargs) => {
&TypeRef::Fn(ref params, variadic, is_unsafe) => {
let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
Substitution::from_iter(Interner, params.iter().map(|(_, tr)| ctx.lower_ty(tr)))
});
TyKind::Function(FnPointer {
num_binders: 0, // FIXME lower `for<'a> fn()` correctly
sig: FnSig { abi: (), safety: Safety::Safe, variadic: *is_varargs },
sig: FnSig {
abi: (),
safety: if is_unsafe { Safety::Unsafe } else { Safety::Safe },
variadic,
},
substitution: FnSubst(substs),
})
.intern(Interner)
Expand Down Expand Up @@ -1573,7 +1577,12 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
.with_type_param_mode(ParamLoweringMode::Variable);
let ret = ctx_ret.lower_ty(&data.ret_type);
let generics = generics(db.upcast(), def.into());
let sig = CallableSig::from_params_and_return(params, ret, data.is_varargs());
let sig = CallableSig::from_params_and_return(
params,
ret,
data.is_varargs(),
if data.has_unsafe_kw() { Safety::Unsafe } else { Safety::Safe },
);
make_binders(db, &generics, sig)
}

Expand Down Expand Up @@ -1617,7 +1626,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe))
}

/// Build the type of a tuple struct constructor.
Expand All @@ -1644,7 +1653,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders();
Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
Binders::new(binders, CallableSig::from_params_and_return(params, ret, false, Safety::Safe))
}

/// Build the type of a tuple enum variant constructor.
Expand Down
40 changes: 38 additions & 2 deletions crates/hir-ty/src/tests/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,23 @@ fn test() {
)
}

#[test]
fn if_else_adjust_for_branches_discard_type_var() {
check_no_mismatches(
r#"
fn test() {
let f = || {
if true {
&""
} else {
""
}
};
}
"#,
);
}

#[test]
fn match_first_coerce() {
check_no_mismatches(
Expand Down Expand Up @@ -182,6 +199,22 @@ fn test() {
);
}

#[test]
fn match_adjust_for_branches_discard_type_var() {
check_no_mismatches(
r#"
fn test() {
let f = || {
match 0i32 {
0i32 => &"",
_ => "",
}
};
}
"#,
);
}

#[test]
fn return_coerce_unknown() {
check_types(
Expand Down Expand Up @@ -357,7 +390,7 @@ fn test() {
let f: fn(u32) -> isize = foo;
// ^^^ adjustments: Pointer(ReifyFnPointer)
let f: unsafe fn(u32) -> isize = foo;
// ^^^ adjustments: Pointer(ReifyFnPointer)
// ^^^ adjustments: Pointer(ReifyFnPointer), Pointer(UnsafeFnPointer)
}",
);
}
Expand Down Expand Up @@ -388,7 +421,10 @@ fn coerce_closure_to_fn_ptr() {
check_no_mismatches(
r"
fn test() {
let f: fn(u32) -> isize = |x| { 1 };
let f: fn(u32) -> u32 = |x| x;
// ^^^^^ adjustments: Pointer(ClosureFnPointer(Safe))
let f: unsafe fn(u32) -> u32 = |x| x;
// ^^^^^ adjustments: Pointer(ClosureFnPointer(Unsafe))
}",
);
}
Expand Down
Loading

0 comments on commit 79923c3

Please sign in to comment.