aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs17
-rw-r--r--crates/ra_assists/src/handlers/add_impl.rs4
-rw-r--r--crates/ra_assists/src/handlers/add_missing_impl_members.rs34
-rw-r--r--crates/ra_assists/src/handlers/add_new.rs5
-rw-r--r--crates/ra_assists/src/handlers/inline_local_variable.rs2
-rw-r--r--crates/ra_assists/src/handlers/introduce_variable.rs2
-rw-r--r--crates/ra_assists/src/handlers/merge_imports.rs4
-rw-r--r--crates/ra_assists/src/handlers/move_bounds.rs3
-rw-r--r--crates/ra_assists/src/handlers/reorder_fields.rs230
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_hir/src/source_analyzer.rs38
-rw-r--r--crates/ra_hir_def/src/adt.rs20
-rw-r--r--crates/ra_hir_def/src/attr.rs1
-rw-r--r--crates/ra_hir_def/src/body.rs72
-rw-r--r--crates/ra_hir_def/src/body/lower.rs66
-rw-r--r--crates/ra_hir_def/src/data.rs43
-rw-r--r--crates/ra_hir_def/src/diagnostics.rs2
-rw-r--r--crates/ra_hir_def/src/expr.rs33
-rw-r--r--crates/ra_hir_def/src/generics.rs2
-rw-r--r--crates/ra_hir_def/src/lang_item.rs5
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs14
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs2
-rw-r--r--crates/ra_hir_def/src/nameres/tests/incremental.rs6
-rw-r--r--crates/ra_hir_def/src/path.rs5
-rw-r--r--crates/ra_hir_def/src/path/lower.rs2
-rw-r--r--crates/ra_hir_def/src/path/lower/lower_use.rs2
-rw-r--r--crates/ra_hir_def/src/type_ref.rs4
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs2
-rw-r--r--crates/ra_hir_expand/src/quote.rs2
-rw-r--r--crates/ra_hir_ty/Cargo.toml2
-rw-r--r--crates/ra_hir_ty/src/db.rs9
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs31
-rw-r--r--crates/ra_hir_ty/src/display.rs26
-rw-r--r--crates/ra_hir_ty/src/expr.rs137
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs2
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs45
-rw-r--r--crates/ra_hir_ty/src/tests.rs50
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs31
-rw-r--r--crates/ra_hir_ty/src/traits.rs27
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs92
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/tls.rs231
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs1
-rw-r--r--crates/ra_ide/src/completion/complete_fn_param.rs30
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs4
-rw-r--r--crates/ra_ide/src/completion/complete_unqualified_path.rs2
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs13
-rw-r--r--crates/ra_ide/src/display/function_signature.rs21
-rw-r--r--crates/ra_ide/src/inlay_hints.rs61
-rw-r--r--crates/ra_ide/src/references.rs2
-rw-r--r--crates/ra_ide/src/syntax_tree.rs8
-rw-r--r--crates/ra_ide/src/typing.rs2
-rw-r--r--crates/ra_ide_db/src/defs.rs2
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs36
-rw-r--r--crates/ra_mbe/src/tests.rs99
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs40
-rw-r--r--crates/ra_parser/src/grammar/types.rs15
-rw-r--r--crates/ra_parser/src/syntax_kind/generated.rs328
-rw-r--r--crates/ra_proc_macro_srv/Cargo.toml5
-rw-r--r--crates/ra_proc_macro_srv/src/dylib.rs211
-rw-r--r--crates/ra_proc_macro_srv/src/lib.rs36
-rw-r--r--crates/ra_proc_macro_srv/src/rustc_server.rs4
-rw-r--r--crates/ra_proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt188
-rw-r--r--crates/ra_proc_macro_srv/src/tests/mod.rs47
-rw-r--r--crates/ra_proc_macro_srv/src/tests/utils.rs65
-rw-r--r--crates/ra_prof/src/lib.rs15
-rw-r--r--crates/ra_syntax/src/ast.rs44
-rw-r--r--crates/ra_syntax/src/ast/edit.rs19
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs32
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs229
-rw-r--r--crates/ra_syntax/src/ast/generated/nodes.rs556
-rw-r--r--crates/ra_syntax/src/ast/generated/tokens.rs2741
-rw-r--r--crates/ra_syntax/src/ast/make.rs3
-rw-r--r--crates/ra_syntax/src/ast/traits.rs41
-rw-r--r--crates/ra_syntax/src/lib.rs5
-rw-r--r--crates/ra_syntax/src/parsing/lexer.rs77
-rw-r--r--crates/ra_syntax/src/ptr.rs17
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0049_unstarted_raw_string_with_ascii.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0050_unstarted_raw_byte_string_with_ascii.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0005_symbols.txt6
-rw-r--r--crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/err/0003_C++_semicolon.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0007_stray_curly_in_file.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0008_item_block_recovery.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0009_broken_struct_type_parameter.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0011_extern_struct.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0012_broken_lambda.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/err/0013_invalid_type.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0016_missing_semi.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0017_incomplete_binexpr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0018_incomplete_fn.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0019_let_recover.rast14
-rw-r--r--crates/ra_syntax/test_data/parser/err/0022_bad_exprs.rast24
-rw-r--r--crates/ra_syntax/test_data/parser/err/0023_mismatched_paren.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast20
-rw-r--r--crates/ra_syntax/test_data/parser/err/0025_nope.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0031_block_inner_attrs.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/err/0035_use_recover.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/err/0036_partial_use.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0001_array_type_missing_semi.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0003_pointer_type_no_mutability.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0007_async_without_semicolon.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0008_pub_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0013_static_underscore.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast49
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs3
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0001_trait_item_list.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast34
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0008_path_part.rast16
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0009_loop_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0012_type_item_where_clause.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0013_pointer_type_mut.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0014_never_type.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0015_continue_expr.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0017_array_type.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0019_unary_expr.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0020_use_star.rast20
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0021_impl_item_list.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0022_crate_visibility.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0023_placeholder_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0024_slice_pat.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0025_slice_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0026_tuple_pat_fields.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0027_ref_pat.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0029_cast_expr.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0032_fn_pointer_type.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0033_reference_type;.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0034_break_expr.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0037_qual_paths.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0038_full_range_expr.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0040_crate_keyword_vis.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0042_call_expr.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0043_use_alias.rast30
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0046_singleton_tuple_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0050_fn_decl.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0051_unit_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0052_path_type.rast14
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0053_path_expr.rast16
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0056_where_clause.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0058_range_pat.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0060_extern_crate.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast26
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0062_mod_contents.rast14
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0063_impl_def_neg.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0067_crate_path.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0072_return_expr.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0073_type_item_type_params.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0075_block.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0077_try_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0078_type_item.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0083_struct_items.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0084_paren_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0085_expr_literals.rast20
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0090_type_param_default.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0093_index_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0095_placeholder_pat.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0096_no_semi_after_block.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0100_for_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0103_array_expr.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0105_block_expr.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0106_lambda_expr.rast14
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0107_method_call_expr.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0108_tuple_expr.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0110_use_path.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0113_nocontentexpr.rast28
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0114_tuple_struct_where.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0117_macro_call_type.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0123_param_list_vararg.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0125_crate_keyword_path.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0130_let_stmt.rast18
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0130_try_block_expr.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0131_existential_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0132_box_expr.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0138_expression_after_block.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0142_for_range_from.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0144_dot_dot_pat.rast82
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0150_array_attrs.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0151_trait_alias.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0158_binop_resets_statementness.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0158_lambda_ret_block.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0006_inner_attributes.rast20
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0007_extern_crate.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0008_mod_item.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0009_use_item.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0010_use_path_segments.rast14
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0011_outer_attribute.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0012_visibility.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast20
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0014_use_tree.rast26
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0015_use_tree.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0016_struct_flavors.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0018_struct_type_params.rast28
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0020_type_param_bounds.rast24
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0023_static_items.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0024_const_item.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0028_operator_binding_power.rast22
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0029_range_forms.rast36
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0030_string_suffixes.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0030_traits.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0031_extern.rast120
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0032_where_for.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0033_label_break.rast16
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0034_crate_path_in_call.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.rast432
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0036_fully_qualified.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0041_raw_keywords.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0042_ufcs_call_list.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0043_complex_assignment.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0044_let_attrs.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0045_block_inner_attrs.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0046_extern_inner_attributes.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0047_minus_in_inner_pattern.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0048_compound_assignment.rast26
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0049_async_block.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0050_async_block_as_argument.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0052_for_range_block.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.rast6
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0060_as_range.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0061_match_full_range.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.rast2
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0063_variadic_fun.rast12
-rw-r--r--crates/ra_tt/src/lib.rs57
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs12
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs4
-rw-r--r--crates/rust-analyzer/src/world.rs4
-rw-r--r--crates/stdx/src/lib.rs16
280 files changed, 3500 insertions, 4971 deletions
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index 64444ee3a..b63b4d81a 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -180,7 +180,7 @@ trait Trait<T> {
180} 180}
181 181
182impl Trait<u32> for () { 182impl Trait<u32> for () {
183 fn foo(&self) -> u32 { unimplemented!() } 183 fn foo(&self) -> u32 { todo!() }
184 184
185} 185}
186"#####, 186"#####,
@@ -607,6 +607,21 @@ impl Walrus {
607} 607}
608 608
609#[test] 609#[test]
610fn doctest_reorder_fields() {
611 check(
612 "reorder_fields",
613 r#####"
614struct Foo {foo: i32, bar: i32};
615const test: Foo = <|>Foo {bar: 0, foo: 1}
616"#####,
617 r#####"
618struct Foo {foo: i32, bar: i32};
619const test: Foo = Foo {foo: 1, bar: 0}
620"#####,
621 )
622}
623
624#[test]
610fn doctest_replace_if_let_with_match() { 625fn doctest_replace_if_let_with_match() {
611 check( 626 check(
612 "replace_if_let_with_match", 627 "replace_if_let_with_match",
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs
index 72a201b6d..6622eadb2 100644
--- a/crates/ra_assists/src/handlers/add_impl.rs
+++ b/crates/ra_assists/src/handlers/add_impl.rs
@@ -1,5 +1,5 @@
1use ra_syntax::{ 1use ra_syntax::{
2 ast::{self, AstNode, AstToken, NameOwner, TypeParamsOwner}, 2 ast::{self, AstNode, NameOwner, TypeParamsOwner},
3 TextUnit, 3 TextUnit,
4}; 4};
5use stdx::{format_to, SepBy}; 5use stdx::{format_to, SepBy};
@@ -42,7 +42,7 @@ pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> {
42 if let Some(type_params) = type_params { 42 if let Some(type_params) = type_params {
43 let lifetime_params = type_params 43 let lifetime_params = type_params
44 .lifetime_params() 44 .lifetime_params()
45 .filter_map(|it| it.lifetime()) 45 .filter_map(|it| it.lifetime_token())
46 .map(|it| it.text().clone()); 46 .map(|it| it.text().clone());
47 let type_params = 47 let type_params =
48 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); 48 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
index 722f207e2..2d6d44980 100644
--- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
@@ -40,7 +40,7 @@ enum AddMissingImplMembersMode {
40// } 40// }
41// 41//
42// impl Trait<u32> for () { 42// impl Trait<u32> for () {
43// fn foo(&self) -> u32 { unimplemented!() } 43// fn foo(&self) -> u32 { todo!() }
44// 44//
45// } 45// }
46// ``` 46// ```
@@ -165,7 +165,7 @@ fn add_missing_impl_members_inner(
165 165
166fn add_body(fn_def: ast::FnDef) -> ast::FnDef { 166fn add_body(fn_def: ast::FnDef) -> ast::FnDef {
167 if fn_def.body().is_none() { 167 if fn_def.body().is_none() {
168 fn_def.with_body(make::block_from_expr(make::expr_unimplemented())) 168 fn_def.with_body(make::block_from_expr(make::expr_todo()))
169 } else { 169 } else {
170 fn_def 170 fn_def
171 } 171 }
@@ -215,8 +215,8 @@ impl Foo for S {
215 fn bar(&self) {} 215 fn bar(&self) {}
216 <|>type Output; 216 <|>type Output;
217 const CONST: usize = 42; 217 const CONST: usize = 42;
218 fn foo(&self) { unimplemented!() } 218 fn foo(&self) { todo!() }
219 fn baz(&self) { unimplemented!() } 219 fn baz(&self) { todo!() }
220 220
221}", 221}",
222 ); 222 );
@@ -250,7 +250,7 @@ struct S;
250 250
251impl Foo for S { 251impl Foo for S {
252 fn bar(&self) {} 252 fn bar(&self) {}
253 <|>fn foo(&self) { unimplemented!() } 253 <|>fn foo(&self) { todo!() }
254 254
255}", 255}",
256 ); 256 );
@@ -268,7 +268,7 @@ impl Foo for S { <|> }",
268trait Foo { fn foo(&self); } 268trait Foo { fn foo(&self); }
269struct S; 269struct S;
270impl Foo for S { 270impl Foo for S {
271 <|>fn foo(&self) { unimplemented!() } 271 <|>fn foo(&self) { todo!() }
272}", 272}",
273 ); 273 );
274 } 274 }
@@ -285,7 +285,7 @@ impl Foo<u32> for S { <|> }",
285trait Foo<T> { fn foo(&self, t: T) -> &T; } 285trait Foo<T> { fn foo(&self, t: T) -> &T; }
286struct S; 286struct S;
287impl Foo<u32> for S { 287impl Foo<u32> for S {
288 <|>fn foo(&self, t: u32) -> &u32 { unimplemented!() } 288 <|>fn foo(&self, t: u32) -> &u32 { todo!() }
289}", 289}",
290 ); 290 );
291 } 291 }
@@ -302,7 +302,7 @@ impl<U> Foo<U> for S { <|> }",
302trait Foo<T> { fn foo(&self, t: T) -> &T; } 302trait Foo<T> { fn foo(&self, t: T) -> &T; }
303struct S; 303struct S;
304impl<U> Foo<U> for S { 304impl<U> Foo<U> for S {
305 <|>fn foo(&self, t: U) -> &U { unimplemented!() } 305 <|>fn foo(&self, t: U) -> &U { todo!() }
306}", 306}",
307 ); 307 );
308 } 308 }
@@ -319,7 +319,7 @@ impl Foo for S {}<|>",
319trait Foo { fn foo(&self); } 319trait Foo { fn foo(&self); }
320struct S; 320struct S;
321impl Foo for S { 321impl Foo for S {
322 <|>fn foo(&self) { unimplemented!() } 322 <|>fn foo(&self) { todo!() }
323}", 323}",
324 ) 324 )
325 } 325 }
@@ -342,7 +342,7 @@ mod foo {
342} 342}
343struct S; 343struct S;
344impl foo::Foo for S { 344impl foo::Foo for S {
345 <|>fn foo(&self, bar: foo::Bar) { unimplemented!() } 345 <|>fn foo(&self, bar: foo::Bar) { todo!() }
346}", 346}",
347 ); 347 );
348 } 348 }
@@ -365,7 +365,7 @@ mod foo {
365} 365}
366struct S; 366struct S;
367impl foo::Foo for S { 367impl foo::Foo for S {
368 <|>fn foo(&self, bar: foo::Bar<u32>) { unimplemented!() } 368 <|>fn foo(&self, bar: foo::Bar<u32>) { todo!() }
369}", 369}",
370 ); 370 );
371 } 371 }
@@ -388,7 +388,7 @@ mod foo {
388} 388}
389struct S; 389struct S;
390impl foo::Foo<u32> for S { 390impl foo::Foo<u32> for S {
391 <|>fn foo(&self, bar: foo::Bar<u32>) { unimplemented!() } 391 <|>fn foo(&self, bar: foo::Bar<u32>) { todo!() }
392}", 392}",
393 ); 393 );
394 } 394 }
@@ -414,7 +414,7 @@ mod foo {
414struct Param; 414struct Param;
415struct S; 415struct S;
416impl foo::Foo<Param> for S { 416impl foo::Foo<Param> for S {
417 <|>fn foo(&self, bar: Param) { unimplemented!() } 417 <|>fn foo(&self, bar: Param) { todo!() }
418}", 418}",
419 ); 419 );
420 } 420 }
@@ -439,7 +439,7 @@ mod foo {
439} 439}
440struct S; 440struct S;
441impl foo::Foo for S { 441impl foo::Foo for S {
442 <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { unimplemented!() } 442 <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { todo!() }
443}", 443}",
444 ); 444 );
445 } 445 }
@@ -464,7 +464,7 @@ mod foo {
464} 464}
465struct S; 465struct S;
466impl foo::Foo for S { 466impl foo::Foo for S {
467 <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { unimplemented!() } 467 <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { todo!() }
468}", 468}",
469 ); 469 );
470 } 470 }
@@ -487,7 +487,7 @@ mod foo {
487} 487}
488struct S; 488struct S;
489impl foo::Foo for S { 489impl foo::Foo for S {
490 <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { unimplemented!() } 490 <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { todo!() }
491}", 491}",
492 ); 492 );
493 } 493 }
@@ -544,7 +544,7 @@ trait Foo {
544struct S; 544struct S;
545impl Foo for S { 545impl Foo for S {
546 <|>type Output; 546 <|>type Output;
547 fn foo(&self) { unimplemented!() } 547 fn foo(&self) { todo!() }
548}"#, 548}"#,
549 ) 549 )
550 } 550 }
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs
index c10397249..240b19fa3 100644
--- a/crates/ra_assists/src/handlers/add_new.rs
+++ b/crates/ra_assists/src/handlers/add_new.rs
@@ -1,8 +1,7 @@
1use hir::Adt; 1use hir::Adt;
2use ra_syntax::{ 2use ra_syntax::{
3 ast::{ 3 ast::{
4 self, AstNode, AstToken, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, 4 self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner,
5 VisibilityOwner,
6 }, 5 },
7 TextUnit, T, 6 TextUnit, T,
8}; 7};
@@ -106,7 +105,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String {
106 if let Some(type_params) = type_params { 105 if let Some(type_params) = type_params {
107 let lifetime_params = type_params 106 let lifetime_params = type_params
108 .lifetime_params() 107 .lifetime_params()
109 .filter_map(|it| it.lifetime()) 108 .filter_map(|it| it.lifetime_token())
110 .map(|it| it.text().clone()); 109 .map(|it| it.text().clone());
111 let type_params = 110 let type_params =
112 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); 111 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs
index 3bfcba8ff..c4fb425b0 100644
--- a/crates/ra_assists/src/handlers/inline_local_variable.rs
+++ b/crates/ra_assists/src/handlers/inline_local_variable.rs
@@ -29,7 +29,7 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> {
29 ast::Pat::BindPat(pat) => pat, 29 ast::Pat::BindPat(pat) => pat,
30 _ => return None, 30 _ => return None,
31 }; 31 };
32 if bind_pat.is_mutable() { 32 if bind_pat.mut_token().is_some() {
33 tested_by!(test_not_inline_mut_variable); 33 tested_by!(test_not_inline_mut_variable);
34 return None; 34 return None;
35 } 35 }
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs
index 8a02f1a32..8d0f7e922 100644
--- a/crates/ra_assists/src/handlers/introduce_variable.rs
+++ b/crates/ra_assists/src/handlers/introduce_variable.rs
@@ -61,7 +61,7 @@ pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> {
61 }; 61 };
62 if is_full_stmt { 62 if is_full_stmt {
63 tested_by!(test_introduce_var_expr_stmt); 63 tested_by!(test_introduce_var_expr_stmt);
64 if !full_stmt.unwrap().has_semi() { 64 if full_stmt.unwrap().semicolon_token().is_none() {
65 buf.push_str(";"); 65 buf.push_str(";");
66 } 66 }
67 edit.replace(expr.syntax().text_range(), buf); 67 edit.replace(expr.syntax().text_range(), buf);
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs
index f8b3ddb4e..0958f52f1 100644
--- a/crates/ra_assists/src/handlers/merge_imports.rs
+++ b/crates/ra_assists/src/handlers/merge_imports.rs
@@ -3,7 +3,7 @@ use std::iter::successors;
3use ra_syntax::{ 3use ra_syntax::{
4 algo::{neighbor, SyntaxRewriter}, 4 algo::{neighbor, SyntaxRewriter},
5 ast::{self, edit::AstNodeEdit, make}, 5 ast::{self, edit::AstNodeEdit, make},
6 AstNode, AstToken, Direction, InsertPosition, SyntaxElement, T, 6 AstNode, Direction, InsertPosition, SyntaxElement, T,
7}; 7};
8 8
9use crate::{Assist, AssistCtx, AssistId}; 9use crate::{Assist, AssistCtx, AssistId};
@@ -82,7 +82,7 @@ fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTre
82 .filter(|it| it.kind() != T!['{'] && it.kind() != T!['}']), 82 .filter(|it| it.kind() != T!['{'] && it.kind() != T!['}']),
83 ); 83 );
84 let use_tree_list = lhs.use_tree_list()?; 84 let use_tree_list = lhs.use_tree_list()?;
85 let pos = InsertPosition::Before(use_tree_list.r_curly()?.syntax().clone().into()); 85 let pos = InsertPosition::Before(use_tree_list.r_curly_token()?.into());
86 let use_tree_list = use_tree_list.insert_children(pos, to_insert); 86 let use_tree_list = use_tree_list.insert_children(pos, to_insert);
87 Some(lhs.with_use_tree_list(use_tree_list)) 87 Some(lhs.with_use_tree_list(use_tree_list))
88} 88}
diff --git a/crates/ra_assists/src/handlers/move_bounds.rs b/crates/ra_assists/src/handlers/move_bounds.rs
index 93f26f51a..0f26884dc 100644
--- a/crates/ra_assists/src/handlers/move_bounds.rs
+++ b/crates/ra_assists/src/handlers/move_bounds.rs
@@ -2,6 +2,7 @@ use ra_syntax::{
2 ast::{self, edit::AstNodeEdit, make, AstNode, NameOwner, TypeBoundsOwner}, 2 ast::{self, edit::AstNodeEdit, make, AstNode, NameOwner, TypeBoundsOwner},
3 match_ast, 3 match_ast,
4 SyntaxKind::*, 4 SyntaxKind::*,
5 T,
5}; 6};
6 7
7use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
@@ -42,7 +43,7 @@ pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx) -> Option<Assist> {
42 ast::EnumDef(it) => it.variant_list()?.syntax().clone().into(), 43 ast::EnumDef(it) => it.variant_list()?.syntax().clone().into(),
43 ast::StructDef(it) => { 44 ast::StructDef(it) => {
44 it.syntax().children_with_tokens() 45 it.syntax().children_with_tokens()
45 .find(|it| it.kind() == RECORD_FIELD_DEF_LIST || it.kind() == SEMI)? 46 .find(|it| it.kind() == RECORD_FIELD_DEF_LIST || it.kind() == T![;])?
46 }, 47 },
47 _ => return None 48 _ => return None
48 } 49 }
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs
new file mode 100644
index 000000000..692dd1315
--- /dev/null
+++ b/crates/ra_assists/src/handlers/reorder_fields.rs
@@ -0,0 +1,230 @@
1use std::collections::HashMap;
2
3use itertools::Itertools;
4
5use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
6use ra_ide_db::RootDatabase;
7use ra_syntax::{
8 algo, ast,
9 ast::{Name, Path, RecordLit, RecordPat},
10 AstNode, SyntaxKind, SyntaxNode,
11};
12
13use crate::{
14 assist_ctx::{Assist, AssistCtx},
15 AssistId,
16};
17use ra_syntax::ast::{Expr, NameRef};
18
19// Assist: reorder_fields
20//
21// Reorder the fields of record literals and record patterns in the same order as in
22// the definition.
23//
24// ```
25// struct Foo {foo: i32, bar: i32};
26// const test: Foo = <|>Foo {bar: 0, foo: 1}
27// ```
28// ->
29// ```
30// struct Foo {foo: i32, bar: i32};
31// const test: Foo = Foo {foo: 1, bar: 0}
32// ```
33//
34pub(crate) fn reorder_fields(ctx: AssistCtx) -> Option<Assist> {
35 reorder::<RecordLit>(ctx.clone()).or_else(|| reorder::<RecordPat>(ctx))
36}
37
38fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> {
39 let record = ctx.find_node_at_offset::<R>()?;
40 let path = record.syntax().children().find_map(Path::cast)?;
41
42 let ranks = compute_fields_ranks(&path, &ctx)?;
43
44 let fields = get_fields(&record.syntax());
45 let sorted_fields = sorted_by_rank(&fields, |node| {
46 *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value())
47 });
48
49 if sorted_fields == fields {
50 return None;
51 }
52
53 ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", |edit| {
54 for (old, new) in fields.iter().zip(&sorted_fields) {
55 algo::diff(old, new).into_text_edit(edit.text_edit_builder());
56 }
57 edit.target(record.syntax().text_range())
58 })
59}
60
61fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> {
62 use SyntaxKind::*;
63 match node.kind() {
64 RECORD_LIT => vec![RECORD_FIELD],
65 RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT],
66 _ => vec![],
67 }
68}
69
70fn get_field_name(node: &SyntaxNode) -> String {
71 use SyntaxKind::*;
72 match node.kind() {
73 RECORD_FIELD => {
74 if let Some(name) = node.children().find_map(NameRef::cast) {
75 return name.to_string();
76 }
77 node.children().find_map(Expr::cast).map(|expr| expr.to_string()).unwrap_or_default()
78 }
79 BIND_PAT | RECORD_FIELD_PAT => {
80 node.children().find_map(Name::cast).map(|n| n.to_string()).unwrap_or_default()
81 }
82 _ => String::new(),
83 }
84}
85
86fn get_fields(record: &SyntaxNode) -> Vec<SyntaxNode> {
87 let kinds = get_fields_kind(record);
88 record.children().flat_map(|n| n.children()).filter(|n| kinds.contains(&n.kind())).collect()
89}
90
91fn sorted_by_rank(
92 fields: &[SyntaxNode],
93 get_rank: impl Fn(&SyntaxNode) -> usize,
94) -> Vec<SyntaxNode> {
95 fields.iter().cloned().sorted_by_key(get_rank).collect()
96}
97
98fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<Struct> {
99 match sema.resolve_path(path) {
100 Some(PathResolution::Def(ModuleDef::Adt(Adt::Struct(s)))) => Some(s),
101 _ => None,
102 }
103}
104
105fn compute_fields_ranks(path: &Path, ctx: &AssistCtx) -> Option<HashMap<String, usize>> {
106 Some(
107 struct_definition(path, ctx.sema)?
108 .fields(ctx.db)
109 .iter()
110 .enumerate()
111 .map(|(idx, field)| (field.name(ctx.db).to_string(), idx))
112 .collect(),
113 )
114}
115
116#[cfg(test)]
117mod tests {
118 use crate::helpers::{check_assist, check_assist_not_applicable};
119
120 use super::*;
121
122 #[test]
123 fn not_applicable_if_sorted() {
124 check_assist_not_applicable(
125 reorder_fields,
126 r#"
127 struct Foo {
128 foo: i32,
129 bar: i32,
130 }
131
132 const test: Foo = <|>Foo { foo: 0, bar: 0 };
133 "#,
134 )
135 }
136
137 #[test]
138 fn trivial_empty_fields() {
139 check_assist_not_applicable(
140 reorder_fields,
141 r#"
142 struct Foo {};
143 const test: Foo = <|>Foo {}
144 "#,
145 )
146 }
147
148 #[test]
149 fn reorder_struct_fields() {
150 check_assist(
151 reorder_fields,
152 r#"
153 struct Foo {foo: i32, bar: i32};
154 const test: Foo = <|>Foo {bar: 0, foo: 1}
155 "#,
156 r#"
157 struct Foo {foo: i32, bar: i32};
158 const test: Foo = <|>Foo {foo: 1, bar: 0}
159 "#,
160 )
161 }
162
163 #[test]
164 fn reorder_struct_pattern() {
165 check_assist(
166 reorder_fields,
167 r#"
168 struct Foo { foo: i64, bar: i64, baz: i64 }
169
170 fn f(f: Foo) -> {
171 match f {
172 <|>Foo { baz: 0, ref mut bar, .. } => (),
173 _ => ()
174 }
175 }
176 "#,
177 r#"
178 struct Foo { foo: i64, bar: i64, baz: i64 }
179
180 fn f(f: Foo) -> {
181 match f {
182 <|>Foo { ref mut bar, baz: 0, .. } => (),
183 _ => ()
184 }
185 }
186 "#,
187 )
188 }
189
190 #[test]
191 fn reorder_with_extra_field() {
192 check_assist(
193 reorder_fields,
194 r#"
195 struct Foo {
196 foo: String,
197 bar: String,
198 }
199
200 impl Foo {
201 fn new() -> Foo {
202 let foo = String::new();
203 <|>Foo {
204 bar: foo.clone(),
205 extra: "Extra field",
206 foo,
207 }
208 }
209 }
210 "#,
211 r#"
212 struct Foo {
213 foo: String,
214 bar: String,
215 }
216
217 impl Foo {
218 fn new() -> Foo {
219 let foo = String::new();
220 <|>Foo {
221 foo,
222 bar: foo.clone(),
223 extra: "Extra field",
224 }
225 }
226 }
227 "#,
228 )
229 }
230}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 5ba5254fd..a00136da1 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -129,6 +129,7 @@ mod handlers {
129 mod replace_unwrap_with_match; 129 mod replace_unwrap_with_match;
130 mod split_import; 130 mod split_import;
131 mod add_from_impl_for_enum; 131 mod add_from_impl_for_enum;
132 mod reorder_fields;
132 133
133 pub(crate) fn all() -> &'static [AssistHandler] { 134 pub(crate) fn all() -> &'static [AssistHandler] {
134 &[ 135 &[
@@ -170,6 +171,7 @@ mod handlers {
170 // These are manually sorted for better priorities 171 // These are manually sorted for better priorities
171 add_missing_impl_members::add_missing_impl_members, 172 add_missing_impl_members::add_missing_impl_members,
172 add_missing_impl_members::add_missing_default_members, 173 add_missing_impl_members::add_missing_default_members,
174 reorder_fields::reorder_fields,
173 ] 175 ]
174 } 176 }
175} 177}
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index 45631f8fd..58ae6ce41 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -139,7 +139,7 @@ impl SourceAnalyzer {
139 &self, 139 &self,
140 db: &dyn HirDatabase, 140 db: &dyn HirDatabase,
141 field: &ast::FieldExpr, 141 field: &ast::FieldExpr,
142 ) -> Option<crate::StructField> { 142 ) -> Option<StructField> {
143 let expr_id = self.expr_id(db, &field.clone().into())?; 143 let expr_id = self.expr_id(db, &field.clone().into())?;
144 self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into()) 144 self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into())
145 } 145 }
@@ -148,21 +148,19 @@ impl SourceAnalyzer {
148 &self, 148 &self,
149 db: &dyn HirDatabase, 149 db: &dyn HirDatabase,
150 field: &ast::RecordField, 150 field: &ast::RecordField,
151 ) -> Option<(crate::StructField, Option<Local>)> { 151 ) -> Option<(StructField, Option<Local>)> {
152 let (expr_id, local) = match field.expr() { 152 let expr = field.expr()?;
153 Some(it) => (self.expr_id(db, &it)?, None), 153 let expr_id = self.expr_id(db, &expr)?;
154 None => { 154 let local = if field.name_ref().is_some() {
155 let src = InFile { file_id: self.file_id, value: field }; 155 None
156 let expr_id = self.body_source_map.as_ref()?.field_init_shorthand_expr(src)?; 156 } else {
157 let local_name = field.name_ref()?.as_name(); 157 let local_name = field.field_name()?.as_name();
158 let path = ModPath::from_segments(PathKind::Plain, once(local_name)); 158 let path = ModPath::from_segments(PathKind::Plain, once(local_name));
159 let local = match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { 159 match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
160 Some(ValueNs::LocalBinding(pat_id)) => { 160 Some(ValueNs::LocalBinding(pat_id)) => {
161 Some(Local { pat_id, parent: self.resolver.body_owner()? }) 161 Some(Local { pat_id, parent: self.resolver.body_owner()? })
162 } 162 }
163 _ => None, 163 _ => None,
164 };
165 (expr_id, local)
166 } 164 }
167 }; 165 };
168 let struct_field = self.infer.as_ref()?.record_field_resolution(expr_id)?; 166 let struct_field = self.infer.as_ref()?.record_field_resolution(expr_id)?;
@@ -255,7 +253,7 @@ impl SourceAnalyzer {
255 _ => return None, 253 _ => return None,
256 }; 254 };
257 255
258 let (variant, missing_fields) = 256 let (variant, missing_fields, _exhaustive) =
259 record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?; 257 record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;
260 let res = self.missing_fields(db, krate, substs, variant, missing_fields); 258 let res = self.missing_fields(db, krate, substs, variant, missing_fields);
261 Some(res) 259 Some(res)
@@ -319,8 +317,7 @@ fn scope_for_offset(
319 if source.file_id != offset.file_id { 317 if source.file_id != offset.file_id {
320 return None; 318 return None;
321 } 319 }
322 let syntax_node_ptr = 320 let syntax_node_ptr = source.value.syntax_node_ptr();
323 source.value.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
324 Some((syntax_node_ptr, scope)) 321 Some((syntax_node_ptr, scope))
325 }) 322 })
326 // find containing scope 323 // find containing scope
@@ -399,8 +396,7 @@ fn adjust(
399 if source.file_id != file_id { 396 if source.file_id != file_id {
400 return None; 397 return None;
401 } 398 }
402 let syntax_node_ptr = 399 let syntax_node_ptr = source.value.syntax_node_ptr();
403 source.value.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
404 Some((syntax_node_ptr, scope)) 400 Some((syntax_node_ptr, scope))
405 }) 401 })
406 .map(|(ptr, scope)| (ptr.range(), scope)) 402 .map(|(ptr, scope)| (ptr.range(), scope))
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index be4b0accb..7c0d93691 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -4,7 +4,6 @@ use std::sync::Arc;
4 4
5use either::Either; 5use either::Either;
6use hir_expand::{ 6use hir_expand::{
7 hygiene::Hygiene,
8 name::{AsName, Name}, 7 name::{AsName, Name},
9 InFile, 8 InFile,
10}; 9};
@@ -13,7 +12,7 @@ use ra_prof::profile;
13use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; 12use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner};
14 13
15use crate::{ 14use crate::{
16 attr::Attrs, db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, 15 body::CfgExpander, db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace,
17 type_ref::TypeRef, visibility::RawVisibility, EnumId, HasModule, LocalEnumVariantId, 16 type_ref::TypeRef, visibility::RawVisibility, EnumId, HasModule, LocalEnumVariantId,
18 LocalStructFieldId, Lookup, ModuleId, StructId, UnionId, VariantId, 17 LocalStructFieldId, Lookup, ModuleId, StructId, UnionId, VariantId,
19}; 18};
@@ -125,8 +124,9 @@ fn lower_enum(
125 124
126impl VariantData { 125impl VariantData {
127 fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>, module_id: ModuleId) -> Self { 126 fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>, module_id: ModuleId) -> Self {
127 let mut expander = CfgExpander::new(db, flavor.file_id, module_id.krate);
128 let mut trace = Trace::new_for_arena(); 128 let mut trace = Trace::new_for_arena();
129 match lower_struct(db, &mut trace, &flavor, module_id) { 129 match lower_struct(db, &mut expander, &mut trace, &flavor) {
130 StructKind::Tuple => VariantData::Tuple(trace.into_arena()), 130 StructKind::Tuple => VariantData::Tuple(trace.into_arena()),
131 StructKind::Record => VariantData::Record(trace.into_arena()), 131 StructKind::Record => VariantData::Record(trace.into_arena()),
132 StructKind::Unit => VariantData::Unit, 132 StructKind::Unit => VariantData::Unit,
@@ -178,8 +178,9 @@ impl HasChildSource for VariantId {
178 it.lookup(db).container.module(db), 178 it.lookup(db).container.module(db),
179 ), 179 ),
180 }; 180 };
181 let mut expander = CfgExpander::new(db, src.file_id, module_id.krate);
181 let mut trace = Trace::new_for_map(); 182 let mut trace = Trace::new_for_map();
182 lower_struct(db, &mut trace, &src, module_id); 183 lower_struct(db, &mut expander, &mut trace, &src);
183 src.with_value(trace.into_map()) 184 src.with_value(trace.into_map())
184 } 185 }
185} 186}
@@ -193,16 +194,15 @@ pub enum StructKind {
193 194
194fn lower_struct( 195fn lower_struct(
195 db: &dyn DefDatabase, 196 db: &dyn DefDatabase,
197 expander: &mut CfgExpander,
196 trace: &mut Trace<StructFieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>, 198 trace: &mut Trace<StructFieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>,
197 ast: &InFile<ast::StructKind>, 199 ast: &InFile<ast::StructKind>,
198 module_id: ModuleId,
199) -> StructKind { 200) -> StructKind {
200 let crate_graph = db.crate_graph();
201 match &ast.value { 201 match &ast.value {
202 ast::StructKind::Tuple(fl) => { 202 ast::StructKind::Tuple(fl) => {
203 for (i, fd) in fl.fields().enumerate() { 203 for (i, fd) in fl.fields().enumerate() {
204 let attrs = Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id)); 204 let attrs = expander.parse_attrs(&fd);
205 if !attrs.is_cfg_enabled(&crate_graph[module_id.krate].cfg_options) { 205 if !expander.is_cfg_enabled(&attrs) {
206 continue; 206 continue;
207 } 207 }
208 208
@@ -219,8 +219,8 @@ fn lower_struct(
219 } 219 }
220 ast::StructKind::Record(fl) => { 220 ast::StructKind::Record(fl) => {
221 for fd in fl.fields() { 221 for fd in fl.fields() {
222 let attrs = Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id)); 222 let attrs = expander.parse_attrs(&fd);
223 if !attrs.is_cfg_enabled(&crate_graph[module_id.krate].cfg_options) { 223 if !expander.is_cfg_enabled(&attrs) {
224 continue; 224 continue;
225 } 225 }
226 226
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index 7b0c506b1..2f2e3e5ba 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -93,6 +93,7 @@ impl Attrs {
93 } 93 }
94 94
95 pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { 95 pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool {
96 // FIXME: handle cfg_attr :-)
96 self.by_key("cfg").tt_values().all(|tt| cfg_options.is_cfg_enabled(tt) != Some(false)) 97 self.by_key("cfg").tt_values().all(|tt| cfg_options.is_cfg_enabled(tt) != Some(false))
97 } 98 }
98} 99}
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index 5f9d53ecb..eafaf48c1 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -9,11 +9,14 @@ use drop_bomb::DropBomb;
9use either::Either; 9use either::Either;
10use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId}; 10use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId};
11use ra_arena::{map::ArenaMap, Arena}; 11use ra_arena::{map::ArenaMap, Arena};
12use ra_cfg::CfgOptions;
13use ra_db::CrateId;
12use ra_prof::profile; 14use ra_prof::profile;
13use ra_syntax::{ast, AstNode, AstPtr}; 15use ra_syntax::{ast, AstNode, AstPtr};
14use rustc_hash::FxHashMap; 16use rustc_hash::FxHashMap;
15 17
16use crate::{ 18use crate::{
19 attr::Attrs,
17 db::DefDatabase, 20 db::DefDatabase,
18 expr::{Expr, ExprId, Pat, PatId}, 21 expr::{Expr, ExprId, Pat, PatId},
19 item_scope::BuiltinShadowMode, 22 item_scope::BuiltinShadowMode,
@@ -24,25 +27,59 @@ use crate::{
24 AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, 27 AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId,
25}; 28};
26 29
30/// A subser of Exander that only deals with cfg attributes. We only need it to
31/// avoid cyclic queries in crate def map during enum processing.
32pub(crate) struct CfgExpander {
33 cfg_options: CfgOptions,
34 hygiene: Hygiene,
35}
36
27pub(crate) struct Expander { 37pub(crate) struct Expander {
38 cfg_expander: CfgExpander,
28 crate_def_map: Arc<CrateDefMap>, 39 crate_def_map: Arc<CrateDefMap>,
29 current_file_id: HirFileId, 40 current_file_id: HirFileId,
30 hygiene: Hygiene,
31 ast_id_map: Arc<AstIdMap>, 41 ast_id_map: Arc<AstIdMap>,
32 module: ModuleId, 42 module: ModuleId,
33 recursive_limit: usize, 43 recursive_limit: usize,
34} 44}
35 45
46impl CfgExpander {
47 pub(crate) fn new(
48 db: &dyn DefDatabase,
49 current_file_id: HirFileId,
50 krate: CrateId,
51 ) -> CfgExpander {
52 let hygiene = Hygiene::new(db.upcast(), current_file_id);
53 let cfg_options = db.crate_graph()[krate].cfg_options.clone();
54 CfgExpander { cfg_options, hygiene }
55 }
56
57 pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs {
58 Attrs::new(owner, &self.hygiene)
59 }
60
61 pub(crate) fn is_cfg_enabled(&self, attrs: &Attrs) -> bool {
62 attrs.is_cfg_enabled(&self.cfg_options)
63 }
64}
65
36impl Expander { 66impl Expander {
37 pub(crate) fn new( 67 pub(crate) fn new(
38 db: &dyn DefDatabase, 68 db: &dyn DefDatabase,
39 current_file_id: HirFileId, 69 current_file_id: HirFileId,
40 module: ModuleId, 70 module: ModuleId,
41 ) -> Expander { 71 ) -> Expander {
72 let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
42 let crate_def_map = db.crate_def_map(module.krate); 73 let crate_def_map = db.crate_def_map(module.krate);
43 let hygiene = Hygiene::new(db.upcast(), current_file_id);
44 let ast_id_map = db.ast_id_map(current_file_id); 74 let ast_id_map = db.ast_id_map(current_file_id);
45 Expander { crate_def_map, current_file_id, hygiene, ast_id_map, module, recursive_limit: 0 } 75 Expander {
76 cfg_expander,
77 crate_def_map,
78 current_file_id,
79 ast_id_map,
80 module,
81 recursive_limit: 0,
82 }
46 } 83 }
47 84
48 pub(crate) fn enter_expand<T: ast::AstNode>( 85 pub(crate) fn enter_expand<T: ast::AstNode>(
@@ -75,7 +112,7 @@ impl Expander {
75 ast_id_map: mem::take(&mut self.ast_id_map), 112 ast_id_map: mem::take(&mut self.ast_id_map),
76 bomb: DropBomb::new("expansion mark dropped"), 113 bomb: DropBomb::new("expansion mark dropped"),
77 }; 114 };
78 self.hygiene = Hygiene::new(db.upcast(), file_id); 115 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
79 self.current_file_id = file_id; 116 self.current_file_id = file_id;
80 self.ast_id_map = db.ast_id_map(file_id); 117 self.ast_id_map = db.ast_id_map(file_id);
81 self.recursive_limit += 1; 118 self.recursive_limit += 1;
@@ -91,7 +128,7 @@ impl Expander {
91 } 128 }
92 129
93 pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { 130 pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
94 self.hygiene = Hygiene::new(db.upcast(), mark.file_id); 131 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
95 self.current_file_id = mark.file_id; 132 self.current_file_id = mark.file_id;
96 self.ast_id_map = mem::take(&mut mark.ast_id_map); 133 self.ast_id_map = mem::take(&mut mark.ast_id_map);
97 self.recursive_limit -= 1; 134 self.recursive_limit -= 1;
@@ -102,8 +139,16 @@ impl Expander {
102 InFile { file_id: self.current_file_id, value } 139 InFile { file_id: self.current_file_id, value }
103 } 140 }
104 141
142 pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs {
143 self.cfg_expander.parse_attrs(owner)
144 }
145
146 pub(crate) fn is_cfg_enabled(&self, attrs: &Attrs) -> bool {
147 self.cfg_expander.is_cfg_enabled(attrs)
148 }
149
105 fn parse_path(&mut self, path: ast::Path) -> Option<Path> { 150 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
106 Path::from_src(path, &self.hygiene) 151 Path::from_src(path, &self.cfg_expander.hygiene)
107 } 152 }
108 153
109 fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> { 154 fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> {
@@ -142,7 +187,7 @@ pub struct Body {
142 pub item_scope: ItemScope, 187 pub item_scope: ItemScope,
143} 188}
144 189
145pub type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; 190pub type ExprPtr = AstPtr<ast::Expr>;
146pub type ExprSource = InFile<ExprPtr>; 191pub type ExprSource = InFile<ExprPtr>;
147 192
148pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; 193pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
@@ -236,11 +281,11 @@ impl Index<PatId> for Body {
236 281
237impl BodySourceMap { 282impl BodySourceMap {
238 pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> { 283 pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
239 self.expr_map_back[expr] 284 self.expr_map_back[expr].clone()
240 } 285 }
241 286
242 pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> { 287 pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
243 let src = node.map(|it| Either::Left(AstPtr::new(it))); 288 let src = node.map(|it| AstPtr::new(it));
244 self.expr_map.get(&src).cloned() 289 self.expr_map.get(&src).cloned()
245 } 290 }
246 291
@@ -249,13 +294,8 @@ impl BodySourceMap {
249 self.expansions.get(&src).cloned() 294 self.expansions.get(&src).cloned()
250 } 295 }
251 296
252 pub fn field_init_shorthand_expr(&self, node: InFile<&ast::RecordField>) -> Option<ExprId> {
253 let src = node.map(|it| Either::Right(AstPtr::new(it)));
254 self.expr_map.get(&src).cloned()
255 }
256
257 pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> { 297 pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
258 self.pat_map_back[pat] 298 self.pat_map_back[pat].clone()
259 } 299 }
260 300
261 pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> { 301 pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
@@ -264,6 +304,6 @@ impl BodySourceMap {
264 } 304 }
265 305
266 pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { 306 pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> {
267 self.field_map[&(expr, field)] 307 self.field_map[&(expr, field)].clone()
268 } 308 }
269} 309}
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 032037c8c..c057dc8f2 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -2,9 +2,7 @@
2//! representation. 2//! representation.
3 3
4use either::Either; 4use either::Either;
5
6use hir_expand::{ 5use hir_expand::{
7 hygiene::Hygiene,
8 name::{name, AsName, Name}, 6 name::{name, AsName, Name},
9 MacroDefId, MacroDefKind, 7 MacroDefId, MacroDefKind,
10}; 8};
@@ -18,10 +16,8 @@ use ra_syntax::{
18}; 16};
19use test_utils::tested_by; 17use test_utils::tested_by;
20 18
21use super::{ExprSource, PatSource};
22use crate::{ 19use crate::{
23 adt::StructKind, 20 adt::StructKind,
24 attr::Attrs,
25 body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax}, 21 body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax},
26 builtin_type::{BuiltinFloat, BuiltinInt}, 22 builtin_type::{BuiltinFloat, BuiltinInt},
27 db::DefDatabase, 23 db::DefDatabase,
@@ -31,12 +27,13 @@ use crate::{
31 }, 27 },
32 item_scope::BuiltinShadowMode, 28 item_scope::BuiltinShadowMode,
33 path::GenericArgs, 29 path::GenericArgs,
34 path::Path,
35 type_ref::{Mutability, TypeRef}, 30 type_ref::{Mutability, TypeRef},
36 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, HasModule, Intern, 31 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId,
37 ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, 32 StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
38}; 33};
39 34
35use super::{ExprSource, PatSource};
36
40pub(super) fn lower( 37pub(super) fn lower(
41 db: &dyn DefDatabase, 38 db: &dyn DefDatabase,
42 def: DefWithBodyId, 39 def: DefWithBodyId,
@@ -104,9 +101,8 @@ impl ExprCollector<'_> {
104 } 101 }
105 102
106 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { 103 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
107 let ptr = Either::Left(ptr);
108 let src = self.expander.to_source(ptr); 104 let src = self.expander.to_source(ptr);
109 let id = self.make_expr(expr, Ok(src)); 105 let id = self.make_expr(expr, Ok(src.clone()));
110 self.source_map.expr_map.insert(src, id); 106 self.source_map.expr_map.insert(src, id);
111 id 107 id
112 } 108 }
@@ -115,13 +111,6 @@ impl ExprCollector<'_> {
115 fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { 111 fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
116 self.make_expr(expr, Err(SyntheticSyntax)) 112 self.make_expr(expr, Err(SyntheticSyntax))
117 } 113 }
118 fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId {
119 let ptr = Either::Right(ptr);
120 let src = self.expander.to_source(ptr);
121 let id = self.make_expr(expr, Ok(src));
122 self.source_map.expr_map.insert(src, id);
123 id
124 }
125 fn empty_block(&mut self) -> ExprId { 114 fn empty_block(&mut self) -> ExprId {
126 self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None }) 115 self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None })
127 } 116 }
@@ -136,7 +125,7 @@ impl ExprCollector<'_> {
136 125
137 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { 126 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
138 let src = self.expander.to_source(ptr); 127 let src = self.expander.to_source(ptr);
139 let id = self.make_pat(pat, Ok(src)); 128 let id = self.make_pat(pat, Ok(src.clone()));
140 self.source_map.pat_map.insert(src, id); 129 self.source_map.pat_map.insert(src, id);
141 id 130 id
142 } 131 }
@@ -291,7 +280,7 @@ impl ExprCollector<'_> {
291 ast::Expr::ParenExpr(e) => { 280 ast::Expr::ParenExpr(e) => {
292 let inner = self.collect_expr_opt(e.expr()); 281 let inner = self.collect_expr_opt(e.expr());
293 // make the paren expr point to the inner expression as well 282 // make the paren expr point to the inner expression as well
294 let src = self.expander.to_source(Either::Left(syntax_ptr)); 283 let src = self.expander.to_source(syntax_ptr);
295 self.source_map.expr_map.insert(src, inner); 284 self.source_map.expr_map.insert(src, inner);
296 inner 285 inner
297 } 286 }
@@ -300,7 +289,6 @@ impl ExprCollector<'_> {
300 self.alloc_expr(Expr::Return { expr }, syntax_ptr) 289 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
301 } 290 }
302 ast::Expr::RecordLit(e) => { 291 ast::Expr::RecordLit(e) => {
303 let crate_graph = self.db.crate_graph();
304 let path = e.path().and_then(|path| self.expander.parse_path(path)); 292 let path = e.path().and_then(|path| self.expander.parse_path(path));
305 let mut field_ptrs = Vec::new(); 293 let mut field_ptrs = Vec::new();
306 let record_lit = if let Some(nfl) = e.record_field_list() { 294 let record_lit = if let Some(nfl) = e.record_field_list() {
@@ -308,31 +296,17 @@ impl ExprCollector<'_> {
308 .fields() 296 .fields()
309 .inspect(|field| field_ptrs.push(AstPtr::new(field))) 297 .inspect(|field| field_ptrs.push(AstPtr::new(field)))
310 .filter_map(|field| { 298 .filter_map(|field| {
311 let module_id = ContainerId::DefWithBodyId(self.def).module(self.db); 299 let attrs = self.expander.parse_attrs(&field);
312 let attrs = Attrs::new( 300 if !self.expander.is_cfg_enabled(&attrs) {
313 &field,
314 &Hygiene::new(self.db.upcast(), self.expander.current_file_id),
315 );
316
317 if !attrs.is_cfg_enabled(&crate_graph[module_id.krate].cfg_options) {
318 return None; 301 return None;
319 } 302 }
303 let name = field.field_name()?.as_name();
320 304
321 Some(RecordLitField { 305 Some(RecordLitField {
322 name: field 306 name,
323 .name_ref() 307 expr: match field.expr() {
324 .map(|nr| nr.as_name()) 308 Some(e) => self.collect_expr(e),
325 .unwrap_or_else(Name::missing), 309 None => self.missing_expr(),
326 expr: if let Some(e) = field.expr() {
327 self.collect_expr(e)
328 } else if let Some(nr) = field.name_ref() {
329 // field shorthand
330 self.alloc_expr_field_shorthand(
331 Expr::Path(Path::from_name_ref(&nr)),
332 AstPtr::new(&field),
333 )
334 } else {
335 self.missing_expr()
336 }, 310 },
337 }) 311 })
338 }) 312 })
@@ -372,7 +346,7 @@ impl ExprCollector<'_> {
372 } 346 }
373 ast::Expr::RefExpr(e) => { 347 ast::Expr::RefExpr(e) => {
374 let expr = self.collect_expr_opt(e.expr()); 348 let expr = self.collect_expr_opt(e.expr());
375 let mutability = Mutability::from_mutable(e.is_mut()); 349 let mutability = Mutability::from_mutable(e.mut_token().is_some());
376 self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr) 350 self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr)
377 } 351 }
378 ast::Expr::PrefixExpr(e) => { 352 ast::Expr::PrefixExpr(e) => {
@@ -587,7 +561,8 @@ impl ExprCollector<'_> {
587 let pattern = match &pat { 561 let pattern = match &pat {
588 ast::Pat::BindPat(bp) => { 562 ast::Pat::BindPat(bp) => {
589 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); 563 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
590 let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref()); 564 let annotation =
565 BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
591 let subpat = bp.pat().map(|subpat| self.collect_pat(subpat)); 566 let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
592 if annotation == BindingAnnotation::Unannotated && subpat.is_none() { 567 if annotation == BindingAnnotation::Unannotated && subpat.is_none() {
593 // This could also be a single-segment path pattern. To 568 // This could also be a single-segment path pattern. To
@@ -628,7 +603,7 @@ impl ExprCollector<'_> {
628 } 603 }
629 ast::Pat::RefPat(p) => { 604 ast::Pat::RefPat(p) => {
630 let pat = self.collect_pat_opt(p.pat()); 605 let pat = self.collect_pat_opt(p.pat());
631 let mutability = Mutability::from_mutable(p.is_mut()); 606 let mutability = Mutability::from_mutable(p.mut_token().is_some());
632 Pat::Ref { pat, mutability } 607 Pat::Ref { pat, mutability }
633 } 608 }
634 ast::Pat::PathPat(p) => { 609 ast::Pat::PathPat(p) => {
@@ -667,7 +642,9 @@ impl ExprCollector<'_> {
667 }); 642 });
668 fields.extend(iter); 643 fields.extend(iter);
669 644
670 Pat::Record { path, args: fields } 645 let ellipsis = record_field_pat_list.dotdot_token().is_some();
646
647 Pat::Record { path, args: fields, ellipsis }
671 } 648 }
672 ast::Pat::SlicePat(p) => { 649 ast::Pat::SlicePat(p) => {
673 let SlicePatComponents { prefix, slice, suffix } = p.components(); 650 let SlicePatComponents { prefix, slice, suffix } = p.components();
@@ -688,7 +665,6 @@ impl ExprCollector<'_> {
688 Pat::Missing 665 Pat::Missing
689 } 666 }
690 } 667 }
691
692 // FIXME: implement 668 // FIXME: implement
693 ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, 669 ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
694 }; 670 };
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index e793ad874..56a20c5bd 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -20,7 +20,7 @@ use crate::{
20 type_ref::{Mutability, TypeBound, TypeRef}, 20 type_ref::{Mutability, TypeBound, TypeRef},
21 visibility::RawVisibility, 21 visibility::RawVisibility,
22 AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, 22 AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule,
23 ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, 23 ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
24}; 24};
25 25
26#[derive(Debug, Clone, PartialEq, Eq)] 26#[derive(Debug, Clone, PartialEq, Eq)]
@@ -74,7 +74,7 @@ impl FunctionData {
74 TypeRef::unit() 74 TypeRef::unit()
75 }; 75 };
76 76
77 let ret_type = if src.value.is_async() { 77 let ret_type = if src.value.async_token().is_some() {
78 let future_impl = desugar_future_path(ret_type); 78 let future_impl = desugar_future_path(ret_type);
79 let ty_bound = TypeBound::Path(future_impl); 79 let ty_bound = TypeBound::Path(future_impl);
80 TypeRef::ImplTrait(vec![ty_bound]) 80 TypeRef::ImplTrait(vec![ty_bound])
@@ -135,7 +135,7 @@ impl TraitData {
135 pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { 135 pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> {
136 let src = tr.lookup(db).source(db); 136 let src = tr.lookup(db).source(db);
137 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 137 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
138 let auto = src.value.is_auto(); 138 let auto = src.value.auto_token().is_some();
139 let ast_id_map = db.ast_id_map(src.file_id); 139 let ast_id_map = db.ast_id_map(src.file_id);
140 140
141 let container = AssocContainerId::TraitId(tr); 141 let container = AssocContainerId::TraitId(tr);
@@ -212,16 +212,23 @@ impl ImplData {
212 212
213 let target_trait = src.value.target_trait().map(TypeRef::from_ast); 213 let target_trait = src.value.target_trait().map(TypeRef::from_ast);
214 let target_type = TypeRef::from_ast_opt(src.value.target_type()); 214 let target_type = TypeRef::from_ast_opt(src.value.target_type());
215 let is_negative = src.value.is_negative(); 215 let is_negative = src.value.excl_token().is_some();
216 let module_id = impl_loc.container.module(db); 216 let module_id = impl_loc.container.module(db);
217 217
218 let mut items = Vec::new(); 218 let mut items = Vec::new();
219 219
220 if let Some(item_list) = src.value.item_list() { 220 if let Some(item_list) = src.value.item_list() {
221 items.extend(collect_impl_items(db, item_list.impl_items(), src.file_id, id)); 221 let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id);
222 items.extend(collect_impl_items(
223 db,
224 &mut expander,
225 item_list.impl_items(),
226 src.file_id,
227 id,
228 ));
222 items.extend(collect_impl_items_in_macros( 229 items.extend(collect_impl_items_in_macros(
223 db, 230 db,
224 module_id, 231 &mut expander,
225 &src.with_value(item_list), 232 &src.with_value(item_list),
226 id, 233 id,
227 )); 234 ));
@@ -268,18 +275,17 @@ impl ConstData {
268 275
269fn collect_impl_items_in_macros( 276fn collect_impl_items_in_macros(
270 db: &dyn DefDatabase, 277 db: &dyn DefDatabase,
271 module_id: ModuleId, 278 expander: &mut Expander,
272 impl_def: &InFile<ast::ItemList>, 279 impl_def: &InFile<ast::ItemList>,
273 id: ImplId, 280 id: ImplId,
274) -> Vec<AssocItemId> { 281) -> Vec<AssocItemId> {
275 let mut expander = Expander::new(db, impl_def.file_id, module_id);
276 let mut res = Vec::new(); 282 let mut res = Vec::new();
277 283
278 // We set a limit to protect against infinite recursion 284 // We set a limit to protect against infinite recursion
279 let limit = 100; 285 let limit = 100;
280 286
281 for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) { 287 for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) {
282 res.extend(collect_impl_items_in_macro(db, &mut expander, m, id, limit)) 288 res.extend(collect_impl_items_in_macro(db, expander, m, id, limit))
283 } 289 }
284 290
285 res 291 res
@@ -300,6 +306,7 @@ fn collect_impl_items_in_macro(
300 let items: InFile<ast::MacroItems> = expander.to_source(items); 306 let items: InFile<ast::MacroItems> = expander.to_source(items);
301 let mut res = collect_impl_items( 307 let mut res = collect_impl_items(
302 db, 308 db,
309 expander,
303 items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())), 310 items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())),
304 items.file_id, 311 items.file_id,
305 id, 312 id,
@@ -319,32 +326,26 @@ fn collect_impl_items_in_macro(
319 326
320fn collect_impl_items( 327fn collect_impl_items(
321 db: &dyn DefDatabase, 328 db: &dyn DefDatabase,
329 expander: &mut Expander,
322 impl_items: impl Iterator<Item = ImplItem>, 330 impl_items: impl Iterator<Item = ImplItem>,
323 file_id: crate::HirFileId, 331 file_id: crate::HirFileId,
324 id: ImplId, 332 id: ImplId,
325) -> Vec<AssocItemId> { 333) -> Vec<AssocItemId> {
326 let items = db.ast_id_map(file_id); 334 let items = db.ast_id_map(file_id);
327 let crate_graph = db.crate_graph();
328 let module_id = id.lookup(db).container.module(db);
329 335
330 impl_items 336 impl_items
331 .filter_map(|item_node| match item_node { 337 .filter_map(|item_node| match item_node {
332 ast::ImplItem::FnDef(it) => { 338 ast::ImplItem::FnDef(it) => {
339 let attrs = expander.parse_attrs(&it);
340 if !expander.is_cfg_enabled(&attrs) {
341 return None;
342 }
333 let def = FunctionLoc { 343 let def = FunctionLoc {
334 container: AssocContainerId::ImplId(id), 344 container: AssocContainerId::ImplId(id),
335 ast_id: AstId::new(file_id, items.ast_id(&it)), 345 ast_id: AstId::new(file_id, items.ast_id(&it)),
336 } 346 }
337 .intern(db); 347 .intern(db);
338 348 Some(def.into())
339 if !db
340 .function_data(def)
341 .attrs
342 .is_cfg_enabled(&crate_graph[module_id.krate].cfg_options)
343 {
344 None
345 } else {
346 Some(def.into())
347 }
348 } 349 }
349 ast::ImplItem::ConstDef(it) => { 350 ast::ImplItem::ConstDef(it) => {
350 let def = ConstLoc { 351 let def = ConstLoc {
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs
index 095498429..cfa0f2f76 100644
--- a/crates/ra_hir_def/src/diagnostics.rs
+++ b/crates/ra_hir_def/src/diagnostics.rs
@@ -20,7 +20,7 @@ impl Diagnostic for UnresolvedModule {
20 "unresolved module".to_string() 20 "unresolved module".to_string()
21 } 21 }
22 fn source(&self) -> InFile<SyntaxNodePtr> { 22 fn source(&self) -> InFile<SyntaxNodePtr> {
23 InFile { file_id: self.file, value: self.decl.into() } 23 InFile { file_id: self.file, value: self.decl.clone().into() }
24 } 24 }
25 fn as_any(&self) -> &(dyn Any + Send + 'static) { 25 fn as_any(&self) -> &(dyn Any + Send + 'static) {
26 self 26 self
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs
index 197bbe9bd..e11bdf3ec 100644
--- a/crates/ra_hir_def/src/expr.rs
+++ b/crates/ra_hir_def/src/expr.rs
@@ -376,35 +376,14 @@ pub enum Pat {
376 Wild, 376 Wild,
377 Tuple(Vec<PatId>), 377 Tuple(Vec<PatId>),
378 Or(Vec<PatId>), 378 Or(Vec<PatId>),
379 Record { 379 Record { path: Option<Path>, args: Vec<RecordFieldPat>, ellipsis: bool },
380 path: Option<Path>, 380 Range { start: ExprId, end: ExprId },
381 args: Vec<RecordFieldPat>, 381 Slice { prefix: Vec<PatId>, slice: Option<PatId>, suffix: Vec<PatId> },
382 // FIXME: 'ellipsis' option
383 },
384 Range {
385 start: ExprId,
386 end: ExprId,
387 },
388 Slice {
389 prefix: Vec<PatId>,
390 slice: Option<PatId>,
391 suffix: Vec<PatId>,
392 },
393 Path(Path), 382 Path(Path),
394 Lit(ExprId), 383 Lit(ExprId),
395 Bind { 384 Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> },
396 mode: BindingAnnotation, 385 TupleStruct { path: Option<Path>, args: Vec<PatId> },
397 name: Name, 386 Ref { pat: PatId, mutability: Mutability },
398 subpat: Option<PatId>,
399 },
400 TupleStruct {
401 path: Option<Path>,
402 args: Vec<PatId>,
403 },
404 Ref {
405 pat: PatId,
406 mutability: Mutability,
407 },
408} 387}
409 388
410impl Pat { 389impl Pat {
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
index b687ce2b2..d850244c4 100644
--- a/crates/ra_hir_def/src/generics.rs
+++ b/crates/ra_hir_def/src/generics.rs
@@ -194,7 +194,7 @@ impl GenericParams {
194 } 194 }
195 195
196 fn add_where_predicate_from_bound(&mut self, bound: ast::TypeBound, type_ref: TypeRef) { 196 fn add_where_predicate_from_bound(&mut self, bound: ast::TypeBound, type_ref: TypeRef) {
197 if bound.has_question_mark() { 197 if bound.question_token().is_some() {
198 // FIXME: remove this bound 198 // FIXME: remove this bound
199 return; 199 return;
200 } 200 }
diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs
index 01b367278..d96ac8c0a 100644
--- a/crates/ra_hir_def/src/lang_item.rs
+++ b/crates/ra_hir_def/src/lang_item.rs
@@ -4,6 +4,7 @@
4//! features, such as Fn family of traits. 4//! features, such as Fn family of traits.
5use std::sync::Arc; 5use std::sync::Arc;
6 6
7use ra_prof::profile;
7use ra_syntax::SmolStr; 8use ra_syntax::SmolStr;
8use rustc_hash::FxHashMap; 9use rustc_hash::FxHashMap;
9 10
@@ -78,6 +79,8 @@ impl LangItems {
78 79
79 /// Salsa query. This will look for lang items in a specific crate. 80 /// Salsa query. This will look for lang items in a specific crate.
80 pub(crate) fn crate_lang_items_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<LangItems> { 81 pub(crate) fn crate_lang_items_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<LangItems> {
82 let _p = profile("crate_lang_items_query");
83
81 let mut lang_items = LangItems::default(); 84 let mut lang_items = LangItems::default();
82 85
83 let crate_def_map = db.crate_def_map(krate); 86 let crate_def_map = db.crate_def_map(krate);
@@ -95,6 +98,7 @@ impl LangItems {
95 db: &dyn DefDatabase, 98 db: &dyn DefDatabase,
96 module: ModuleId, 99 module: ModuleId,
97 ) -> Option<Arc<LangItems>> { 100 ) -> Option<Arc<LangItems>> {
101 let _p = profile("module_lang_items_query");
98 let mut lang_items = LangItems::default(); 102 let mut lang_items = LangItems::default();
99 lang_items.collect_lang_items(db, module); 103 lang_items.collect_lang_items(db, module);
100 if lang_items.items.is_empty() { 104 if lang_items.items.is_empty() {
@@ -111,6 +115,7 @@ impl LangItems {
111 start_crate: CrateId, 115 start_crate: CrateId,
112 item: SmolStr, 116 item: SmolStr,
113 ) -> Option<LangItemTarget> { 117 ) -> Option<LangItemTarget> {
118 let _p = profile("lang_item_query");
114 let lang_items = db.crate_lang_items(start_crate); 119 let lang_items = db.crate_lang_items(start_crate);
115 let start_crate_target = lang_items.items.get(&item); 120 let start_crate_target = lang_items.items.get(&item);
116 if let Some(target) = start_crate_target { 121 if let Some(target) = start_crate_target {
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 8fe3f8617..98c74fe25 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -462,6 +462,14 @@ impl DefCollector<'_> {
462 Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { 462 Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
463 tested_by!(glob_enum); 463 tested_by!(glob_enum);
464 // glob import from enum => just import all the variants 464 // glob import from enum => just import all the variants
465
466 // XXX: urgh, so this works by accident! Here, we look at
467 // the enum data, and, in theory, this might require us to
468 // look back at the crate_def_map, creating a cycle. For
469 // example, `enum E { crate::some_macro!(); }`. Luckely, the
470 // only kind of macro that is allowed inside enum is a
471 // `cfg_macro`, and we don't need to run name resolution for
472 // it, but this is sheer luck!
465 let enum_data = self.db.enum_data(e); 473 let enum_data = self.db.enum_data(e);
466 let resolutions = enum_data 474 let resolutions = enum_data
467 .variants 475 .variants
@@ -977,11 +985,7 @@ impl ModCollector<'_, '_> {
977 } 985 }
978 986
979 fn is_cfg_enabled(&self, attrs: &Attrs) -> bool { 987 fn is_cfg_enabled(&self, attrs: &Attrs) -> bool {
980 // FIXME: handle cfg_attr :-) 988 attrs.is_cfg_enabled(self.def_collector.cfg_options)
981 attrs
982 .by_key("cfg")
983 .tt_values()
984 .all(|tt| self.def_collector.cfg_options.is_cfg_enabled(tt) != Some(false))
985 } 989 }
986} 990}
987 991
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index a9dff3a5d..afd538e4a 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -287,7 +287,7 @@ impl RawItemsCollector {
287 let visibility = RawVisibility::from_ast_with_hygiene(module.visibility(), &self.hygiene); 287 let visibility = RawVisibility::from_ast_with_hygiene(module.visibility(), &self.hygiene);
288 288
289 let ast_id = self.source_ast_id_map.ast_id(&module); 289 let ast_id = self.source_ast_id_map.ast_id(&module);
290 if module.has_semi() { 290 if module.semicolon_token().is_some() {
291 let item = 291 let item =
292 self.raw_items.modules.alloc(ModuleData::Declaration { name, visibility, ast_id }); 292 self.raw_items.modules.alloc(ModuleData::Declaration { name, visibility, ast_id });
293 self.push_item(current_module, attrs, RawItemKind::Module(item)); 293 self.push_item(current_module, attrs, RawItemKind::Module(item));
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs
index 496fc6b08..87165ac33 100644
--- a/crates/ra_hir_def/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs
@@ -32,6 +32,9 @@ fn typing_inside_a_function_should_not_invalidate_def_map() {
32 32
33 use crate::foo::bar::Baz; 33 use crate::foo::bar::Baz;
34 34
35 enum E { A, B }
36 use E::*;
37
35 fn foo() -> i32 { 38 fn foo() -> i32 {
36 1 + 1 39 1 + 1
37 } 40 }
@@ -46,6 +49,9 @@ fn typing_inside_a_function_should_not_invalidate_def_map() {
46 49
47 use crate::foo::bar::Baz; 50 use crate::foo::bar::Baz;
48 51
52 enum E { A, B }
53 use E::*;
54
49 fn foo() -> i32 { 92 } 55 fn foo() -> i32 { 92 }
50 ", 56 ",
51 ); 57 );
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index 904080341..91c7b3e09 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -134,11 +134,6 @@ impl Path {
134 lower::lower_path(path, hygiene) 134 lower::lower_path(path, hygiene)
135 } 135 }
136 136
137 /// Converts an `ast::NameRef` into a single-identifier `Path`.
138 pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
139 Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] }
140 }
141
142 /// Converts a known mod path to `Path`. 137 /// Converts a known mod path to `Path`.
143 pub(crate) fn from_known_path( 138 pub(crate) fn from_known_path(
144 path: ModPath, 139 path: ModPath,
diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs
index 3c13cb2c7..0f806d6fb 100644
--- a/crates/ra_hir_def/src/path/lower.rs
+++ b/crates/ra_hir_def/src/path/lower.rs
@@ -28,7 +28,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
28 loop { 28 loop {
29 let segment = path.segment()?; 29 let segment = path.segment()?;
30 30
31 if segment.coloncolon().is_some() { 31 if segment.coloncolon_token().is_some() {
32 kind = PathKind::Abs; 32 kind = PathKind::Abs;
33 } 33 }
34 34
diff --git a/crates/ra_hir_def/src/path/lower/lower_use.rs b/crates/ra_hir_def/src/path/lower/lower_use.rs
index 6ec944228..5b6854b0f 100644
--- a/crates/ra_hir_def/src/path/lower/lower_use.rs
+++ b/crates/ra_hir_def/src/path/lower/lower_use.rs
@@ -34,7 +34,7 @@ pub(crate) fn lower_use_tree(
34 let alias = tree.alias().map(|a| { 34 let alias = tree.alias().map(|a| {
35 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) 35 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
36 }); 36 });
37 let is_glob = tree.star().is_some(); 37 let is_glob = tree.star_token().is_some();
38 if let Some(ast_path) = tree.path() { 38 if let Some(ast_path) = tree.path() {
39 // Handle self in a path. 39 // Handle self in a path.
40 // E.g. `use something::{self, <...>}` 40 // E.g. `use something::{self, <...>}`
diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs
index 01cc392db..ea29c4176 100644
--- a/crates/ra_hir_def/src/type_ref.rs
+++ b/crates/ra_hir_def/src/type_ref.rs
@@ -77,7 +77,7 @@ impl TypeRef {
77 } 77 }
78 ast::TypeRef::PointerType(inner) => { 78 ast::TypeRef::PointerType(inner) => {
79 let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); 79 let inner_ty = TypeRef::from_ast_opt(inner.type_ref());
80 let mutability = Mutability::from_mutable(inner.is_mut()); 80 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
81 TypeRef::RawPtr(Box::new(inner_ty), mutability) 81 TypeRef::RawPtr(Box::new(inner_ty), mutability)
82 } 82 }
83 ast::TypeRef::ArrayType(inner) => { 83 ast::TypeRef::ArrayType(inner) => {
@@ -88,7 +88,7 @@ impl TypeRef {
88 } 88 }
89 ast::TypeRef::ReferenceType(inner) => { 89 ast::TypeRef::ReferenceType(inner) => {
90 let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); 90 let inner_ty = TypeRef::from_ast_opt(inner.type_ref());
91 let mutability = Mutability::from_mutable(inner.is_mut()); 91 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
92 TypeRef::Reference(Box::new(inner_ty), mutability) 92 TypeRef::Reference(Box::new(inner_ty), mutability)
93 } 93 }
94 ast::TypeRef::PlaceholderType(_inner) => TypeRef::Placeholder, 94 ast::TypeRef::PlaceholderType(_inner) => TypeRef::Placeholder,
diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs
index 5643ecdce..a3ca302c2 100644
--- a/crates/ra_hir_expand/src/ast_id_map.rs
+++ b/crates/ra_hir_expand/src/ast_id_map.rs
@@ -90,7 +90,7 @@ impl AstIdMap {
90 } 90 }
91 91
92 pub(crate) fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> { 92 pub(crate) fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> {
93 self.arena[id.raw].cast::<N>().unwrap() 93 self.arena[id.raw].clone().cast::<N>().unwrap()
94 } 94 }
95 95
96 fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId { 96 fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId {
diff --git a/crates/ra_hir_expand/src/quote.rs b/crates/ra_hir_expand/src/quote.rs
index 3fd4233da..219bc2097 100644
--- a/crates/ra_hir_expand/src/quote.rs
+++ b/crates/ra_hir_expand/src/quote.rs
@@ -232,7 +232,7 @@ mod tests {
232 let quoted = quote!(#a); 232 let quoted = quote!(#a);
233 assert_eq!(quoted.to_string(), "hello"); 233 assert_eq!(quoted.to_string(), "hello");
234 let t = format!("{:?}", quoted); 234 let t = format!("{:?}", quoted);
235 assert_eq!(t, "Subtree { delimiter: None, token_trees: [Leaf(Ident(Ident { text: \"hello\", id: TokenId(4294967295) }))] }"); 235 assert_eq!(t, "SUBTREE $\n IDENT hello 4294967295");
236 } 236 }
237 237
238 #[test] 238 #[test]
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 9a4a7aa6f..59efc1c31 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -24,6 +24,8 @@ ra_prof = { path = "../ra_prof" }
24ra_syntax = { path = "../ra_syntax" } 24ra_syntax = { path = "../ra_syntax" }
25test_utils = { path = "../test_utils" } 25test_utils = { path = "../test_utils" }
26 26
27scoped-tls = "1"
28
27chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" } 29chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" }
28chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" } 30chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" }
29chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" } 31chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" }
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index 1462b053f..33da16b48 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -11,7 +11,7 @@ use ra_db::{impl_intern_key, salsa, CrateId, Upcast};
11use ra_prof::profile; 11use ra_prof::profile;
12 12
13use crate::{ 13use crate::{
14 method_resolution::CrateImplDefs, 14 method_resolution::{CrateImplDefs, TyFingerprint},
15 traits::{chalk, AssocTyValue, Impl}, 15 traits::{chalk, AssocTyValue, Impl},
16 Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty, 16 Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty,
17 TyDefId, TypeCtor, ValueTyDefId, 17 TyDefId, TypeCtor, ValueTyDefId,
@@ -65,7 +65,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
65 fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; 65 fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>;
66 66
67 #[salsa::invoke(crate::traits::impls_for_trait_query)] 67 #[salsa::invoke(crate::traits::impls_for_trait_query)]
68 fn impls_for_trait(&self, krate: CrateId, trait_: TraitId) -> Arc<[ImplId]>; 68 fn impls_for_trait(
69 &self,
70 krate: CrateId,
71 trait_: TraitId,
72 self_ty_fp: Option<TyFingerprint>,
73 ) -> Arc<[ImplId]>;
69 74
70 // Interned IDs for Chalk integration 75 // Interned IDs for Chalk integration
71 #[salsa::interned] 76 #[salsa::interned]
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index 8cbce1168..927896d6f 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -21,7 +21,7 @@ impl Diagnostic for NoSuchField {
21 } 21 }
22 22
23 fn source(&self) -> InFile<SyntaxNodePtr> { 23 fn source(&self) -> InFile<SyntaxNodePtr> {
24 InFile { file_id: self.file, value: self.field.into() } 24 InFile { file_id: self.file, value: self.field.clone().into() }
25 } 25 }
26 26
27 fn as_any(&self) -> &(dyn Any + Send + 'static) { 27 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -45,7 +45,7 @@ impl Diagnostic for MissingFields {
45 buf 45 buf
46 } 46 }
47 fn source(&self) -> InFile<SyntaxNodePtr> { 47 fn source(&self) -> InFile<SyntaxNodePtr> {
48 InFile { file_id: self.file, value: self.field_list.into() } 48 InFile { file_id: self.file, value: self.field_list.clone().into() }
49 } 49 }
50 fn as_any(&self) -> &(dyn Any + Send + 'static) { 50 fn as_any(&self) -> &(dyn Any + Send + 'static) {
51 self 51 self
@@ -63,6 +63,29 @@ impl AstDiagnostic for MissingFields {
63} 63}
64 64
65#[derive(Debug)] 65#[derive(Debug)]
66pub struct MissingPatFields {
67 pub file: HirFileId,
68 pub field_list: AstPtr<ast::RecordFieldPatList>,
69 pub missed_fields: Vec<Name>,
70}
71
72impl Diagnostic for MissingPatFields {
73 fn message(&self) -> String {
74 let mut buf = String::from("Missing structure fields:\n");
75 for field in &self.missed_fields {
76 format_to!(buf, "- {}", field);
77 }
78 buf
79 }
80 fn source(&self) -> InFile<SyntaxNodePtr> {
81 InFile { file_id: self.file, value: self.field_list.clone().into() }
82 }
83 fn as_any(&self) -> &(dyn Any + Send + 'static) {
84 self
85 }
86}
87
88#[derive(Debug)]
66pub struct MissingMatchArms { 89pub struct MissingMatchArms {
67 pub file: HirFileId, 90 pub file: HirFileId,
68 pub match_expr: AstPtr<ast::Expr>, 91 pub match_expr: AstPtr<ast::Expr>,
@@ -74,7 +97,7 @@ impl Diagnostic for MissingMatchArms {
74 String::from("Missing match arm") 97 String::from("Missing match arm")
75 } 98 }
76 fn source(&self) -> InFile<SyntaxNodePtr> { 99 fn source(&self) -> InFile<SyntaxNodePtr> {
77 InFile { file_id: self.file, value: self.match_expr.into() } 100 InFile { file_id: self.file, value: self.match_expr.clone().into() }
78 } 101 }
79 fn as_any(&self) -> &(dyn Any + Send + 'static) { 102 fn as_any(&self) -> &(dyn Any + Send + 'static) {
80 self 103 self
@@ -92,7 +115,7 @@ impl Diagnostic for MissingOkInTailExpr {
92 "wrap return expression in Ok".to_string() 115 "wrap return expression in Ok".to_string()
93 } 116 }
94 fn source(&self) -> InFile<SyntaxNodePtr> { 117 fn source(&self) -> InFile<SyntaxNodePtr> {
95 InFile { file_id: self.file, value: self.expr.into() } 118 InFile { file_id: self.file, value: self.expr.clone().into() }
96 } 119 }
97 fn as_any(&self) -> &(dyn Any + Send + 'static) { 120 fn as_any(&self) -> &(dyn Any + Send + 'static) {
98 self 121 self
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index 0e9313aa1..d03bbd5a7 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -247,19 +247,21 @@ impl HirDisplay for ApplicationTy {
247 } 247 }
248 } 248 }
249 TypeCtor::Closure { .. } => { 249 TypeCtor::Closure { .. } => {
250 let sig = self.parameters[0] 250 let sig = self.parameters[0].callable_sig(f.db);
251 .callable_sig(f.db) 251 if let Some(sig) = sig {
252 .expect("first closure parameter should contain signature"); 252 if sig.params().is_empty() {
253 if sig.params().is_empty() { 253 write!(f, "||")?;
254 write!(f, "||")?; 254 } else if f.omit_verbose_types() {
255 } else if f.omit_verbose_types() { 255 write!(f, "|{}|", TYPE_HINT_TRUNCATION)?;
256 write!(f, "|{}|", TYPE_HINT_TRUNCATION)?; 256 } else {
257 write!(f, "|")?;
258 f.write_joined(sig.params(), ", ")?;
259 write!(f, "|")?;
260 };
261 write!(f, " -> {}", sig.ret().display(f.db))?;
257 } else { 262 } else {
258 write!(f, "|")?; 263 write!(f, "{{closure}}")?;
259 f.write_joined(sig.params(), ", ")?; 264 }
260 write!(f, "|")?;
261 };
262 write!(f, " -> {}", sig.ret().display(f.db))?;
263 } 265 }
264 } 266 }
265 Ok(()) 267 Ok(())
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs
index e45e9ea14..69b527f74 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -9,7 +9,7 @@ use rustc_hash::FxHashSet;
9 9
10use crate::{ 10use crate::{
11 db::HirDatabase, 11 db::HirDatabase,
12 diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr}, 12 diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields},
13 utils::variant_data, 13 utils::variant_data,
14 ApplicationTy, InferenceResult, Ty, TypeCtor, 14 ApplicationTy, InferenceResult, Ty, TypeCtor,
15 _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, 15 _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness},
@@ -49,39 +49,95 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
49 if let Some((variant_def, missed_fields, true)) = 49 if let Some((variant_def, missed_fields, true)) =
50 record_literal_missing_fields(db, &self.infer, id, expr) 50 record_literal_missing_fields(db, &self.infer, id, expr)
51 { 51 {
52 // XXX: only look at source_map if we do have missing fields 52 self.create_record_literal_missing_fields_diagnostic(
53 let (_, source_map) = db.body_with_source_map(self.func.into()); 53 id,
54 54 db,
55 if let Ok(source_ptr) = source_map.expr_syntax(id) { 55 variant_def,
56 if let Some(expr) = source_ptr.value.left() { 56 missed_fields,
57 let root = source_ptr.file_syntax(db.upcast()); 57 );
58 if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) {
59 if let Some(field_list) = record_lit.record_field_list() {
60 let variant_data = variant_data(db.upcast(), variant_def);
61 let missed_fields = missed_fields
62 .into_iter()
63 .map(|idx| variant_data.fields()[idx].name.clone())
64 .collect();
65 self.sink.push(MissingFields {
66 file: source_ptr.file_id,
67 field_list: AstPtr::new(&field_list),
68 missed_fields,
69 })
70 }
71 }
72 }
73 }
74 } 58 }
75 if let Expr::Match { expr, arms } = expr { 59 if let Expr::Match { expr, arms } = expr {
76 self.validate_match(id, *expr, arms, db, self.infer.clone()); 60 self.validate_match(id, *expr, arms, db, self.infer.clone());
77 } 61 }
78 } 62 }
63 for (id, pat) in body.pats.iter() {
64 if let Some((variant_def, missed_fields, true)) =
65 record_pattern_missing_fields(db, &self.infer, id, pat)
66 {
67 self.create_record_pattern_missing_fields_diagnostic(
68 id,
69 db,
70 variant_def,
71 missed_fields,
72 );
73 }
74 }
79 let body_expr = &body[body.body_expr]; 75 let body_expr = &body[body.body_expr];
80 if let Expr::Block { tail: Some(t), .. } = body_expr { 76 if let Expr::Block { tail: Some(t), .. } = body_expr {
81 self.validate_results_in_tail_expr(body.body_expr, *t, db); 77 self.validate_results_in_tail_expr(body.body_expr, *t, db);
82 } 78 }
83 } 79 }
84 80
81 fn create_record_literal_missing_fields_diagnostic(
82 &mut self,
83 id: ExprId,
84 db: &dyn HirDatabase,
85 variant_def: VariantId,
86 missed_fields: Vec<LocalStructFieldId>,
87 ) {
88 // XXX: only look at source_map if we do have missing fields
89 let (_, source_map) = db.body_with_source_map(self.func.into());
90
91 if let Ok(source_ptr) = source_map.expr_syntax(id) {
92 let root = source_ptr.file_syntax(db.upcast());
93 if let ast::Expr::RecordLit(record_lit) = &source_ptr.value.to_node(&root) {
94 if let Some(field_list) = record_lit.record_field_list() {
95 let variant_data = variant_data(db.upcast(), variant_def);
96 let missed_fields = missed_fields
97 .into_iter()
98 .map(|idx| variant_data.fields()[idx].name.clone())
99 .collect();
100 self.sink.push(MissingFields {
101 file: source_ptr.file_id,
102 field_list: AstPtr::new(&field_list),
103 missed_fields,
104 })
105 }
106 }
107 }
108 }
109
110 fn create_record_pattern_missing_fields_diagnostic(
111 &mut self,
112 id: PatId,
113 db: &dyn HirDatabase,
114 variant_def: VariantId,
115 missed_fields: Vec<LocalStructFieldId>,
116 ) {
117 // XXX: only look at source_map if we do have missing fields
118 let (_, source_map) = db.body_with_source_map(self.func.into());
119
120 if let Ok(source_ptr) = source_map.pat_syntax(id) {
121 if let Some(expr) = source_ptr.value.as_ref().left() {
122 let root = source_ptr.file_syntax(db.upcast());
123 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
124 if let Some(field_list) = record_pat.record_field_pat_list() {
125 let variant_data = variant_data(db.upcast(), variant_def);
126 let missed_fields = missed_fields
127 .into_iter()
128 .map(|idx| variant_data.fields()[idx].name.clone())
129 .collect();
130 self.sink.push(MissingPatFields {
131 file: source_ptr.file_id,
132 field_list: AstPtr::new(&field_list),
133 missed_fields,
134 })
135 }
136 }
137 }
138 }
139 }
140
85 fn validate_match( 141 fn validate_match(
86 &mut self, 142 &mut self,
87 id: ExprId, 143 id: ExprId,
@@ -147,18 +203,16 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
147 } 203 }
148 204
149 if let Ok(source_ptr) = source_map.expr_syntax(id) { 205 if let Ok(source_ptr) = source_map.expr_syntax(id) {
150 if let Some(expr) = source_ptr.value.left() { 206 let root = source_ptr.file_syntax(db.upcast());
151 let root = source_ptr.file_syntax(db.upcast()); 207 if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) {
152 if let ast::Expr::MatchExpr(match_expr) = expr.to_node(&root) { 208 if let (Some(match_expr), Some(arms)) =
153 if let (Some(match_expr), Some(arms)) = 209 (match_expr.expr(), match_expr.match_arm_list())
154 (match_expr.expr(), match_expr.match_arm_list()) 210 {
155 { 211 self.sink.push(MissingMatchArms {
156 self.sink.push(MissingMatchArms { 212 file: source_ptr.file_id,
157 file: source_ptr.file_id, 213 match_expr: AstPtr::new(&match_expr),
158 match_expr: AstPtr::new(&match_expr), 214 arms: AstPtr::new(&arms),
159 arms: AstPtr::new(&arms), 215 })
160 })
161 }
162 } 216 }
163 } 217 }
164 } 218 }
@@ -189,9 +243,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
189 let (_, source_map) = db.body_with_source_map(self.func.into()); 243 let (_, source_map) = db.body_with_source_map(self.func.into());
190 244
191 if let Ok(source_ptr) = source_map.expr_syntax(id) { 245 if let Ok(source_ptr) = source_map.expr_syntax(id) {
192 if let Some(expr) = source_ptr.value.left() { 246 self.sink
193 self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); 247 .push(MissingOkInTailExpr { file: source_ptr.file_id, expr: source_ptr.value });
194 }
195 } 248 }
196 } 249 }
197 } 250 }
@@ -232,9 +285,9 @@ pub fn record_pattern_missing_fields(
232 infer: &InferenceResult, 285 infer: &InferenceResult,
233 id: PatId, 286 id: PatId,
234 pat: &Pat, 287 pat: &Pat,
235) -> Option<(VariantId, Vec<LocalStructFieldId>)> { 288) -> Option<(VariantId, Vec<LocalStructFieldId>, /*exhaustive*/ bool)> {
236 let fields = match pat { 289 let (fields, exhaustive) = match pat {
237 Pat::Record { path: _, args } => args, 290 Pat::Record { path: _, args, ellipsis } => (args, !ellipsis),
238 _ => return None, 291 _ => return None,
239 }; 292 };
240 293
@@ -254,5 +307,5 @@ pub fn record_pattern_missing_fields(
254 if missed_fields.is_empty() { 307 if missed_fields.is_empty() {
255 return None; 308 return None;
256 } 309 }
257 Some((variant_def, missed_fields)) 310 Some((variant_def, missed_fields, exhaustive))
258} 311}
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index 69bbb4307..078476f76 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -158,7 +158,7 @@ impl<'a> InferenceContext<'a> {
158 Pat::TupleStruct { path: p, args: subpats } => { 158 Pat::TupleStruct { path: p, args: subpats } => {
159 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm, pat) 159 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm, pat)
160 } 160 }
161 Pat::Record { path: p, args: fields } => { 161 Pat::Record { path: p, args: fields, ellipsis: _ } => {
162 self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat) 162 self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat)
163 } 163 }
164 Pat::Path(path) => { 164 Pat::Path(path) => {
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index 74a0bc7db..657284fd0 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -34,7 +34,7 @@ impl TyFingerprint {
34 /// Creates a TyFingerprint for looking up an impl. Only certain types can 34 /// Creates a TyFingerprint for looking up an impl. Only certain types can
35 /// have impls: if we have some `struct S`, we can have an `impl S`, but not 35 /// have impls: if we have some `struct S`, we can have an `impl S`, but not
36 /// `impl &S`. Hence, this will return `None` for reference types and such. 36 /// `impl &S`. Hence, this will return `None` for reference types and such.
37 fn for_impl(ty: &Ty) -> Option<TyFingerprint> { 37 pub(crate) fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
38 match ty { 38 match ty {
39 Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.ctor)), 39 Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.ctor)),
40 _ => None, 40 _ => None,
@@ -45,7 +45,7 @@ impl TyFingerprint {
45#[derive(Debug, PartialEq, Eq)] 45#[derive(Debug, PartialEq, Eq)]
46pub struct CrateImplDefs { 46pub struct CrateImplDefs {
47 impls: FxHashMap<TyFingerprint, Vec<ImplId>>, 47 impls: FxHashMap<TyFingerprint, Vec<ImplId>>,
48 impls_by_trait: FxHashMap<TraitId, Vec<ImplId>>, 48 impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
49} 49}
50 50
51impl CrateImplDefs { 51impl CrateImplDefs {
@@ -59,7 +59,14 @@ impl CrateImplDefs {
59 for impl_id in module_data.scope.impls() { 59 for impl_id in module_data.scope.impls() {
60 match db.impl_trait(impl_id) { 60 match db.impl_trait(impl_id) {
61 Some(tr) => { 61 Some(tr) => {
62 res.impls_by_trait.entry(tr.value.trait_).or_default().push(impl_id); 62 let self_ty = db.impl_self_ty(impl_id);
63 let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
64 res.impls_by_trait
65 .entry(tr.value.trait_)
66 .or_default()
67 .entry(self_ty_fp)
68 .or_default()
69 .push(impl_id);
63 } 70 }
64 None => { 71 None => {
65 let self_ty = db.impl_self_ty(impl_id); 72 let self_ty = db.impl_self_ty(impl_id);
@@ -79,11 +86,39 @@ impl CrateImplDefs {
79 } 86 }
80 87
81 pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ { 88 pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ {
82 self.impls_by_trait.get(&tr).into_iter().flatten().copied() 89 self.impls_by_trait
90 .get(&tr)
91 .into_iter()
92 .flat_map(|m| m.values().flat_map(|v| v.iter().copied()))
93 }
94
95 pub fn lookup_impl_defs_for_trait_and_ty(
96 &self,
97 tr: TraitId,
98 fp: TyFingerprint,
99 ) -> impl Iterator<Item = ImplId> + '_ {
100 self.impls_by_trait
101 .get(&tr)
102 .and_then(|m| m.get(&Some(fp)))
103 .into_iter()
104 .flatten()
105 .copied()
106 .chain(
107 self.impls_by_trait
108 .get(&tr)
109 .and_then(|m| m.get(&None))
110 .into_iter()
111 .flatten()
112 .copied(),
113 )
83 } 114 }
84 115
85 pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { 116 pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a {
86 self.impls.values().chain(self.impls_by_trait.values()).flatten().copied() 117 self.impls
118 .values()
119 .chain(self.impls_by_trait.values().flat_map(|m| m.values()))
120 .flatten()
121 .copied()
87 } 122 }
88} 123}
89 124
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 08723068f..81fc0f63a 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -23,7 +23,7 @@ use insta::assert_snapshot;
23use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; 23use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase};
24use ra_syntax::{ 24use ra_syntax::{
25 algo, 25 algo,
26 ast::{self, AstNode, AstToken}, 26 ast::{self, AstNode},
27}; 27};
28use stdx::format_to; 28use stdx::format_to;
29 29
@@ -82,12 +82,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
82 82
83 for (expr, ty) in inference_result.type_of_expr.iter() { 83 for (expr, ty) in inference_result.type_of_expr.iter() {
84 let syntax_ptr = match body_source_map.expr_syntax(expr) { 84 let syntax_ptr = match body_source_map.expr_syntax(expr) {
85 Ok(sp) => { 85 Ok(sp) => sp.map(|ast| ast.syntax_node_ptr()),
86 sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()))
87 }
88 Err(SyntheticSyntax) => continue, 86 Err(SyntheticSyntax) => continue,
89 }; 87 };
90 types.push((syntax_ptr, ty)); 88 types.push((syntax_ptr.clone(), ty));
91 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) { 89 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) {
92 mismatches.push((syntax_ptr, mismatch)); 90 mismatches.push((syntax_ptr, mismatch));
93 } 91 }
@@ -101,7 +99,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
101 let node = src_ptr.value.to_node(&src_ptr.file_syntax(&db)); 99 let node = src_ptr.value.to_node(&src_ptr.file_syntax(&db));
102 100
103 let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) { 101 let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) {
104 (self_param.self_kw().unwrap().syntax().text_range(), "self".to_string()) 102 (self_param.self_token().unwrap().text_range(), "self".to_string())
105 } else { 103 } else {
106 (src_ptr.value.range(), node.text().to_string().replace("\n", " ")) 104 (src_ptr.value.range(), node.text().to_string().replace("\n", " "))
107 }; 105 };
@@ -409,3 +407,43 @@ fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() {
409 407
410 assert_snapshot!(diagnostics, @r###""###); 408 assert_snapshot!(diagnostics, @r###""###);
411} 409}
410
411#[test]
412fn missing_record_pat_field_diagnostic() {
413 let diagnostics = TestDB::with_files(
414 r"
415 //- /lib.rs
416 struct S { foo: i32, bar: () }
417 fn baz(s: S) {
418 let S { foo: _ } = s;
419 }
420 ",
421 )
422 .diagnostics()
423 .0;
424
425 assert_snapshot!(diagnostics, @r###"
426 "{ foo: _ }": Missing structure fields:
427 - bar
428 "###
429 );
430}
431
432#[test]
433fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
434 let diagnostics = TestDB::with_files(
435 r"
436 //- /lib.rs
437 struct S { foo: i32, bar: () }
438 fn baz(s: S) -> i32 {
439 match s {
440 S { foo, .. } => foo,
441 }
442 }
443 ",
444 )
445 .diagnostics()
446 .0;
447
448 assert_snapshot!(diagnostics, @"");
449}
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index ff4599b71..f2a9b1c40 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -1,10 +1,13 @@
1use std::fs;
2
1use insta::assert_snapshot; 3use insta::assert_snapshot;
2use ra_db::fixture::WithFixture; 4use ra_db::fixture::WithFixture;
3 5use test_utils::project_dir;
4use super::{infer, type_at, type_at_pos};
5 6
6use crate::test_db::TestDB; 7use crate::test_db::TestDB;
7 8
9use super::{infer, type_at, type_at_pos};
10
8#[test] 11#[test]
9fn cfg_impl_def() { 12fn cfg_impl_def() {
10 let (db, pos) = TestDB::with_position( 13 let (db, pos) = TestDB::with_position(
@@ -482,6 +485,30 @@ fn bar() -> u32 {0}
482} 485}
483 486
484#[test] 487#[test]
488#[ignore]
489fn include_accidentally_quadratic() {
490 let file = project_dir().join("crates/ra_syntax/test_data/accidentally_quadratic");
491 let big_file = fs::read_to_string(file).unwrap();
492 let big_file = vec![big_file; 10].join("\n");
493
494 let fixture = r#"
495//- /main.rs
496#[rustc_builtin_macro]
497macro_rules! include {() => {}}
498
499include!("foo.rs");
500
501fn main() {
502 RegisterBlock { }<|>;
503}
504 "#;
505 let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file);
506
507 let (db, pos) = TestDB::with_position(&fixture);
508 assert_eq!("RegisterBlock", type_at_pos(&db, pos));
509}
510
511#[test]
485fn infer_builtin_macros_include_concat() { 512fn infer_builtin_macros_include_concat() {
486 let (db, pos) = TestDB::with_position( 513 let (db, pos) = TestDB::with_position(
487 r#" 514 r#"
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index 5a1e12ce9..43d8d1e80 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -7,7 +7,7 @@ use ra_db::{impl_intern_key, salsa, CrateId};
7use ra_prof::profile; 7use ra_prof::profile;
8use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
9 9
10use crate::{db::HirDatabase, DebruijnIndex}; 10use crate::{db::HirDatabase, method_resolution::TyFingerprint, DebruijnIndex};
11 11
12use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; 12use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
13 13
@@ -40,7 +40,12 @@ pub(crate) fn impls_for_trait_query(
40 db: &dyn HirDatabase, 40 db: &dyn HirDatabase,
41 krate: CrateId, 41 krate: CrateId,
42 trait_: TraitId, 42 trait_: TraitId,
43 self_ty_fp: Option<TyFingerprint>,
43) -> Arc<[ImplId]> { 44) -> Arc<[ImplId]> {
45 // FIXME: We could be a lot smarter here - because of the orphan rules and
46 // the fact that the trait and the self type need to be in the dependency
47 // tree of a crate somewhere for an impl to exist, we could skip looking in
48 // a lot of crates completely
44 let mut impls = FxHashSet::default(); 49 let mut impls = FxHashSet::default();
45 // We call the query recursively here. On the one hand, this means we can 50 // We call the query recursively here. On the one hand, this means we can
46 // reuse results from queries for different crates; on the other hand, this 51 // reuse results from queries for different crates; on the other hand, this
@@ -48,10 +53,13 @@ pub(crate) fn impls_for_trait_query(
48 // ones the user is editing), so this may actually be a waste of memory. I'm 53 // ones the user is editing), so this may actually be a waste of memory. I'm
49 // doing it like this mainly for simplicity for now. 54 // doing it like this mainly for simplicity for now.
50 for dep in &db.crate_graph()[krate].dependencies { 55 for dep in &db.crate_graph()[krate].dependencies {
51 impls.extend(db.impls_for_trait(dep.crate_id, trait_).iter()); 56 impls.extend(db.impls_for_trait(dep.crate_id, trait_, self_ty_fp).iter());
52 } 57 }
53 let crate_impl_defs = db.impls_in_crate(krate); 58 let crate_impl_defs = db.impls_in_crate(krate);
54 impls.extend(crate_impl_defs.lookup_impl_defs_for_trait(trait_)); 59 match self_ty_fp {
60 Some(fp) => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp)),
61 None => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait(trait_)),
62 }
55 impls.into_iter().collect() 63 impls.into_iter().collect()
56} 64}
57 65
@@ -177,7 +185,7 @@ fn solve(
177 185
178 let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL); 186 let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL);
179 187
180 let solution = solver.solve_limited(&context, goal, || { 188 let should_continue = || {
181 context.db.check_canceled(); 189 context.db.check_canceled();
182 let remaining = fuel.get(); 190 let remaining = fuel.get();
183 fuel.set(remaining - 1); 191 fuel.set(remaining - 1);
@@ -185,12 +193,21 @@ fn solve(
185 log::debug!("fuel exhausted"); 193 log::debug!("fuel exhausted");
186 } 194 }
187 remaining > 0 195 remaining > 0
188 }); 196 };
197 let mut solve = || solver.solve_limited(&context, goal, should_continue);
198 // don't set the TLS for Chalk unless Chalk debugging is active, to make
199 // extra sure we only use it for debugging
200 let solution =
201 if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() };
189 202
190 log::debug!("solve({:?}) => {:?}", goal, solution); 203 log::debug!("solve({:?}) => {:?}", goal, solution);
191 solution 204 solution
192} 205}
193 206
207fn is_chalk_debug() -> bool {
208 std::env::var("CHALK_DEBUG").is_ok()
209}
210
194fn solution_from_chalk( 211fn solution_from_chalk(
195 db: &dyn HirDatabase, 212 db: &dyn HirDatabase,
196 solution: chalk_solve::Solution<Interner>, 213 solution: chalk_solve::Solution<Interner>,
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 1bc0f0713..e05fea843 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -16,10 +16,12 @@ use ra_db::{
16 16
17use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; 17use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
18use crate::{ 18use crate::{
19 db::HirDatabase, display::HirDisplay, utils::generics, ApplicationTy, GenericPredicate, 19 db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics,
20 ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 20 ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
21}; 21};
22 22
23pub(super) mod tls;
24
23#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] 25#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
24pub struct Interner; 26pub struct Interner;
25 27
@@ -33,90 +35,85 @@ impl chalk_ir::interner::Interner for Interner {
33 type Identifier = TypeAliasId; 35 type Identifier = TypeAliasId;
34 type DefId = InternId; 36 type DefId = InternId;
35 37
36 // FIXME: implement these
37 fn debug_struct_id( 38 fn debug_struct_id(
38 _type_kind_id: chalk_ir::StructId<Self>, 39 type_kind_id: StructId,
39 _fmt: &mut fmt::Formatter<'_>, 40 fmt: &mut fmt::Formatter<'_>,
40 ) -> Option<fmt::Result> { 41 ) -> Option<fmt::Result> {
41 None 42 tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt)))
42 } 43 }
43 44
44 fn debug_trait_id( 45 fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
45 _type_kind_id: chalk_ir::TraitId<Self>, 46 tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt)))
46 _fmt: &mut fmt::Formatter<'_>,
47 ) -> Option<fmt::Result> {
48 None
49 } 47 }
50 48
51 fn debug_assoc_type_id( 49 fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
52 _id: chalk_ir::AssocTypeId<Self>, 50 tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt)))
53 _fmt: &mut fmt::Formatter<'_>,
54 ) -> Option<fmt::Result> {
55 None
56 } 51 }
57 52
58 fn debug_alias( 53 fn debug_alias(
59 _projection: &chalk_ir::AliasTy<Self>, 54 alias: &chalk_ir::AliasTy<Interner>,
60 _fmt: &mut fmt::Formatter<'_>, 55 fmt: &mut fmt::Formatter<'_>,
61 ) -> Option<fmt::Result> { 56 ) -> Option<fmt::Result> {
62 None 57 tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt)))
63 } 58 }
64 59
65 fn debug_ty(_ty: &chalk_ir::Ty<Self>, _fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { 60 fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
66 None 61 tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt)))
67 } 62 }
68 63
69 fn debug_lifetime( 64 fn debug_lifetime(
70 _lifetime: &chalk_ir::Lifetime<Self>, 65 lifetime: &chalk_ir::Lifetime<Interner>,
71 _fmt: &mut fmt::Formatter<'_>, 66 fmt: &mut fmt::Formatter<'_>,
72 ) -> Option<fmt::Result> { 67 ) -> Option<fmt::Result> {
73 None 68 tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt)))
74 } 69 }
75 70
76 fn debug_parameter( 71 fn debug_parameter(
77 _parameter: &Parameter<Self>, 72 parameter: &Parameter<Interner>,
78 _fmt: &mut fmt::Formatter<'_>, 73 fmt: &mut fmt::Formatter<'_>,
79 ) -> Option<fmt::Result> { 74 ) -> Option<fmt::Result> {
80 None 75 tls::with_current_program(|prog| Some(prog?.debug_parameter(parameter, fmt)))
81 } 76 }
82 77
83 fn debug_goal(_goal: &Goal<Self>, _fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { 78 fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
84 None 79 tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt)))
85 } 80 }
86 81
87 fn debug_goals( 82 fn debug_goals(
88 _goals: &chalk_ir::Goals<Self>, 83 goals: &chalk_ir::Goals<Interner>,
89 _fmt: &mut fmt::Formatter<'_>, 84 fmt: &mut fmt::Formatter<'_>,
90 ) -> Option<fmt::Result> { 85 ) -> Option<fmt::Result> {
91 None 86 tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt)))
92 } 87 }
93 88
94 fn debug_program_clause_implication( 89 fn debug_program_clause_implication(
95 _pci: &chalk_ir::ProgramClauseImplication<Self>, 90 pci: &chalk_ir::ProgramClauseImplication<Interner>,
96 _fmt: &mut fmt::Formatter<'_>, 91 fmt: &mut fmt::Formatter<'_>,
97 ) -> Option<fmt::Result> { 92 ) -> Option<fmt::Result> {
98 None 93 tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt)))
99 } 94 }
100 95
101 fn debug_application_ty( 96 fn debug_application_ty(
102 _application_ty: &chalk_ir::ApplicationTy<Self>, 97 application_ty: &chalk_ir::ApplicationTy<Interner>,
103 _fmt: &mut fmt::Formatter<'_>, 98 fmt: &mut fmt::Formatter<'_>,
104 ) -> Option<fmt::Result> { 99 ) -> Option<fmt::Result> {
105 None 100 tls::with_current_program(|prog| Some(prog?.debug_application_ty(application_ty, fmt)))
106 } 101 }
107 102
108 fn debug_substitution( 103 fn debug_substitution(
109 _substitution: &chalk_ir::Substitution<Self>, 104 substitution: &chalk_ir::Substitution<Interner>,
110 _fmt: &mut fmt::Formatter<'_>, 105 fmt: &mut fmt::Formatter<'_>,
111 ) -> Option<fmt::Result> { 106 ) -> Option<fmt::Result> {
112 None 107 tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt)))
113 } 108 }
114 109
115 fn debug_separator_trait_ref( 110 fn debug_separator_trait_ref(
116 _separator_trait_ref: &chalk_ir::SeparatorTraitRef<Self>, 111 separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
117 _fmt: &mut fmt::Formatter<'_>, 112 fmt: &mut fmt::Formatter<'_>,
118 ) -> Option<fmt::Result> { 113 ) -> Option<fmt::Result> {
119 None 114 tls::with_current_program(|prog| {
115 Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt))
116 })
120 } 117 }
121 118
122 fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> { 119 fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> {
@@ -650,19 +647,22 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
650 debug!("impls_for_trait {:?}", trait_id); 647 debug!("impls_for_trait {:?}", trait_id);
651 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); 648 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id);
652 649
650 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone());
651
652 let self_ty_fp = TyFingerprint::for_impl(&ty);
653
653 // Note: Since we're using impls_for_trait, only impls where the trait 654 // Note: Since we're using impls_for_trait, only impls where the trait
654 // can be resolved should ever reach Chalk. `impl_datum` relies on that 655 // can be resolved should ever reach Chalk. `impl_datum` relies on that
655 // and will panic if the trait can't be resolved. 656 // and will panic if the trait can't be resolved.
656 let mut result: Vec<_> = self 657 let mut result: Vec<_> = self
657 .db 658 .db
658 .impls_for_trait(self.krate, trait_) 659 .impls_for_trait(self.krate, trait_, self_ty_fp)
659 .iter() 660 .iter()
660 .copied() 661 .copied()
661 .map(Impl::ImplDef) 662 .map(Impl::ImplDef)
662 .map(|impl_| impl_.to_chalk(self.db)) 663 .map(|impl_| impl_.to_chalk(self.db))
663 .collect(); 664 .collect();
664 665
665 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone());
666 let arg: Option<Ty> = 666 let arg: Option<Ty> =
667 parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref(&Interner).clone())); 667 parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref(&Interner).clone()));
668 668
diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs
new file mode 100644
index 000000000..d9bbb54a5
--- /dev/null
+++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs
@@ -0,0 +1,231 @@
1//! Implementation of Chalk debug helper functions using TLS.
2use std::fmt;
3
4use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName};
5
6use super::{from_chalk, Interner};
7use crate::{db::HirDatabase, CallableDef, TypeCtor};
8use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId};
9
10pub use unsafe_tls::{set_current_program, with_current_program};
11
12pub struct DebugContext<'a>(&'a (dyn HirDatabase + 'a));
13
14impl DebugContext<'_> {
15 pub fn debug_struct_id(
16 &self,
17 id: super::StructId,
18 f: &mut fmt::Formatter<'_>,
19 ) -> Result<(), fmt::Error> {
20 let type_ctor: TypeCtor = from_chalk(self.0, TypeName::Struct(id));
21 match type_ctor {
22 TypeCtor::Bool => write!(f, "bool")?,
23 TypeCtor::Char => write!(f, "char")?,
24 TypeCtor::Int(t) => write!(f, "{}", t)?,
25 TypeCtor::Float(t) => write!(f, "{}", t)?,
26 TypeCtor::Str => write!(f, "str")?,
27 TypeCtor::Slice => write!(f, "slice")?,
28 TypeCtor::Array => write!(f, "array")?,
29 TypeCtor::RawPtr(m) => write!(f, "*{}", m.as_keyword_for_ptr())?,
30 TypeCtor::Ref(m) => write!(f, "&{}", m.as_keyword_for_ref())?,
31 TypeCtor::Never => write!(f, "!")?,
32 TypeCtor::Tuple { .. } => {
33 write!(f, "()")?;
34 }
35 TypeCtor::FnPtr { .. } => {
36 write!(f, "fn")?;
37 }
38 TypeCtor::FnDef(def) => {
39 let name = match def {
40 CallableDef::FunctionId(ff) => self.0.function_data(ff).name.clone(),
41 CallableDef::StructId(s) => self.0.struct_data(s).name.clone(),
42 CallableDef::EnumVariantId(e) => {
43 let enum_data = self.0.enum_data(e.parent);
44 enum_data.variants[e.local_id].name.clone()
45 }
46 };
47 match def {
48 CallableDef::FunctionId(_) => write!(f, "{{fn {}}}", name)?,
49 CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => {
50 write!(f, "{{ctor {}}}", name)?
51 }
52 }
53 }
54 TypeCtor::Adt(def_id) => {
55 let name = match def_id {
56 AdtId::StructId(it) => self.0.struct_data(it).name.clone(),
57 AdtId::UnionId(it) => self.0.union_data(it).name.clone(),
58 AdtId::EnumId(it) => self.0.enum_data(it).name.clone(),
59 };
60 write!(f, "{}", name)?;
61 }
62 TypeCtor::AssociatedType(type_alias) => {
63 let trait_ = match type_alias.lookup(self.0.upcast()).container {
64 AssocContainerId::TraitId(it) => it,
65 _ => panic!("not an associated type"),
66 };
67 let trait_name = self.0.trait_data(trait_).name.clone();
68 let name = self.0.type_alias_data(type_alias).name.clone();
69 write!(f, "{}::{}", trait_name, name)?;
70 }
71 TypeCtor::Closure { def, expr } => {
72 write!(f, "{{closure {:?} in {:?}}}", expr.into_raw(), def)?;
73 }
74 }
75 Ok(())
76 }
77
78 pub fn debug_trait_id(
79 &self,
80 id: super::TraitId,
81 fmt: &mut fmt::Formatter<'_>,
82 ) -> Result<(), fmt::Error> {
83 let trait_: hir_def::TraitId = from_chalk(self.0, id);
84 let trait_data = self.0.trait_data(trait_);
85 write!(fmt, "{}", trait_data.name)
86 }
87
88 pub fn debug_assoc_type_id(
89 &self,
90 id: super::AssocTypeId,
91 fmt: &mut fmt::Formatter<'_>,
92 ) -> Result<(), fmt::Error> {
93 let type_alias: TypeAliasId = from_chalk(self.0, id);
94 let type_alias_data = self.0.type_alias_data(type_alias);
95 let trait_ = match type_alias.lookup(self.0.upcast()).container {
96 AssocContainerId::TraitId(t) => t,
97 _ => panic!("associated type not in trait"),
98 };
99 let trait_data = self.0.trait_data(trait_);
100 write!(fmt, "{}::{}", trait_data.name, type_alias_data.name)
101 }
102
103 pub fn debug_alias(
104 &self,
105 alias: &AliasTy<Interner>,
106 fmt: &mut fmt::Formatter<'_>,
107 ) -> Result<(), fmt::Error> {
108 let type_alias: TypeAliasId = from_chalk(self.0, alias.associated_ty_id);
109 let type_alias_data = self.0.type_alias_data(type_alias);
110 let trait_ = match type_alias.lookup(self.0.upcast()).container {
111 AssocContainerId::TraitId(t) => t,
112 _ => panic!("associated type not in trait"),
113 };
114 let trait_data = self.0.trait_data(trait_);
115 let params = alias.substitution.parameters(&Interner);
116 write!(
117 fmt,
118 "<{:?} as {}<{:?}>>::{}",
119 &params[0],
120 trait_data.name,
121 &params[1..],
122 type_alias_data.name
123 )
124 }
125
126 pub fn debug_ty(
127 &self,
128 ty: &chalk_ir::Ty<Interner>,
129 fmt: &mut fmt::Formatter<'_>,
130 ) -> Result<(), fmt::Error> {
131 write!(fmt, "{:?}", ty.data(&Interner))
132 }
133
134 pub fn debug_lifetime(
135 &self,
136 lifetime: &Lifetime<Interner>,
137 fmt: &mut fmt::Formatter<'_>,
138 ) -> Result<(), fmt::Error> {
139 write!(fmt, "{:?}", lifetime.data(&Interner))
140 }
141
142 pub fn debug_parameter(
143 &self,
144 parameter: &Parameter<Interner>,
145 fmt: &mut fmt::Formatter<'_>,
146 ) -> Result<(), fmt::Error> {
147 write!(fmt, "{:?}", parameter.data(&Interner).inner_debug())
148 }
149
150 pub fn debug_goal(
151 &self,
152 goal: &Goal<Interner>,
153 fmt: &mut fmt::Formatter<'_>,
154 ) -> Result<(), fmt::Error> {
155 let goal_data = goal.data(&Interner);
156 write!(fmt, "{:?}", goal_data)
157 }
158
159 pub fn debug_goals(
160 &self,
161 goals: &Goals<Interner>,
162 fmt: &mut fmt::Formatter<'_>,
163 ) -> Result<(), fmt::Error> {
164 write!(fmt, "{:?}", goals.debug(&Interner))
165 }
166
167 pub fn debug_program_clause_implication(
168 &self,
169 pci: &ProgramClauseImplication<Interner>,
170 fmt: &mut fmt::Formatter<'_>,
171 ) -> Result<(), fmt::Error> {
172 write!(fmt, "{:?}", pci.debug(&Interner))
173 }
174
175 pub fn debug_application_ty(
176 &self,
177 application_ty: &chalk_ir::ApplicationTy<Interner>,
178 fmt: &mut fmt::Formatter<'_>,
179 ) -> Result<(), fmt::Error> {
180 write!(fmt, "{:?}", application_ty.debug(&Interner))
181 }
182
183 pub fn debug_substitution(
184 &self,
185 substitution: &chalk_ir::Substitution<Interner>,
186 fmt: &mut fmt::Formatter<'_>,
187 ) -> Result<(), fmt::Error> {
188 write!(fmt, "{:?}", substitution.debug(&Interner))
189 }
190
191 pub fn debug_separator_trait_ref(
192 &self,
193 separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
194 fmt: &mut fmt::Formatter<'_>,
195 ) -> Result<(), fmt::Error> {
196 write!(fmt, "{:?}", separator_trait_ref.debug(&Interner))
197 }
198}
199
200mod unsafe_tls {
201 use super::DebugContext;
202 use crate::db::HirDatabase;
203 use scoped_tls::scoped_thread_local;
204
205 scoped_thread_local!(static PROGRAM: DebugContext);
206
207 pub fn with_current_program<R>(
208 op: impl for<'a> FnOnce(Option<&'a DebugContext<'a>>) -> R,
209 ) -> R {
210 if PROGRAM.is_set() {
211 PROGRAM.with(|prog| op(Some(prog)))
212 } else {
213 op(None)
214 }
215 }
216
217 pub fn set_current_program<OP, R>(p: &dyn HirDatabase, op: OP) -> R
218 where
219 OP: FnOnce() -> R,
220 {
221 let ctx = DebugContext(p);
222 // we're transmuting the lifetime in the DebugContext to static. This is
223 // fine because we only keep the reference for the lifetime of this
224 // function, *and* the only way to access the context is through
225 // `with_current_program`, which hides the lifetime through the `for`
226 // type.
227 let static_p: &DebugContext<'static> =
228 unsafe { std::mem::transmute::<&DebugContext, &DebugContext<'static>>(&ctx) };
229 PROGRAM.set(static_p, || op())
230 }
231}
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index 358b041aa..b5448af5c 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -72,7 +72,6 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Ty
72 } 72 }
73 for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() { 73 for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() {
74 // FIXME: Handle visibility 74 // FIXME: Handle visibility
75 // TODO: add the same behavior with type ?
76 acc.add_tuple_field(ctx, i, &ty); 75 acc.add_tuple_field(ctx, i, &ty);
77 } 76 }
78 } 77 }
diff --git a/crates/ra_ide/src/completion/complete_fn_param.rs b/crates/ra_ide/src/completion/complete_fn_param.rs
index 62ae5ccb4..f84b559fc 100644
--- a/crates/ra_ide/src/completion/complete_fn_param.rs
+++ b/crates/ra_ide/src/completion/complete_fn_param.rs
@@ -1,6 +1,9 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_syntax::{ast, match_ast, AstNode}; 3use ra_syntax::{
4 ast::{self, ModuleItemOwner},
5 match_ast, AstNode,
6};
4use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
5 8
6use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions}; 9use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions};
@@ -16,11 +19,19 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
16 19
17 let mut params = FxHashMap::default(); 20 let mut params = FxHashMap::default();
18 for node in ctx.token.parent().ancestors() { 21 for node in ctx.token.parent().ancestors() {
19 match_ast! { 22 let items = match_ast! {
20 match node { 23 match node {
21 ast::SourceFile(it) => process(it, &mut params), 24 ast::SourceFile(it) => it.items(),
22 ast::ItemList(it) => process(it, &mut params), 25 ast::ItemList(it) => it.items(),
23 _ => (), 26 _ => continue,
27 }
28 };
29 for item in items {
30 if let ast::ModuleItem::FnDef(func) = item {
31 func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| {
32 let text = param.syntax().text().to_string();
33 params.entry(text).or_insert((0, param)).0 += 1;
34 })
24 } 35 }
25 } 36 }
26 } 37 }
@@ -39,15 +50,6 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
39 .lookup_by(lookup) 50 .lookup_by(lookup)
40 .add_to(acc) 51 .add_to(acc)
41 }); 52 });
42
43 fn process<N: ast::FnDefOwner>(node: N, params: &mut FxHashMap<String, (u32, ast::Param)>) {
44 node.functions().filter_map(|it| it.param_list()).flat_map(|it| it.params()).for_each(
45 |param| {
46 let text = param.syntax().text().to_string();
47 params.entry(text).or_insert((0, param)).0 += 1;
48 },
49 )
50 }
51} 53}
52 54
53#[cfg(test)] 55#[cfg(test)]
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs
index ded1ff3bc..fab02945c 100644
--- a/crates/ra_ide/src/completion/complete_trait_impl.rs
+++ b/crates/ra_ide/src/completion/complete_trait_impl.rs
@@ -35,7 +35,7 @@ use hir::{self, Docs, HasSource};
35use ra_assists::utils::get_missing_impl_items; 35use ra_assists::utils::get_missing_impl_items;
36use ra_syntax::{ 36use ra_syntax::{
37 ast::{self, edit, ImplDef}, 37 ast::{self, edit, ImplDef},
38 AstNode, SyntaxKind, SyntaxNode, TextRange, 38 AstNode, SyntaxKind, SyntaxNode, TextRange, T,
39}; 39};
40use ra_text_edit::TextEdit; 40use ra_text_edit::TextEdit;
41 41
@@ -204,7 +204,7 @@ fn make_const_compl_syntax(const_: &ast::ConstDef) -> String {
204 let end = const_ 204 let end = const_
205 .syntax() 205 .syntax()
206 .children_with_tokens() 206 .children_with_tokens()
207 .find(|s| s.kind() == SyntaxKind::SEMI || s.kind() == SyntaxKind::EQ) 207 .find(|s| s.kind() == T![;] || s.kind() == T![=])
208 .map_or(const_end, |f| f.text_range().start()); 208 .map_or(const_end, |f| f.text_range().start());
209 209
210 let len = end - start; 210 let len = end - start;
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs
index efde9bf73..0b0da6ee4 100644
--- a/crates/ra_ide/src/completion/complete_unqualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs
@@ -3,7 +3,7 @@
3use crate::completion::{CompletionContext, Completions}; 3use crate::completion::{CompletionContext, Completions};
4 4
5pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 5pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
6 if !(ctx.is_trivial_path && !ctx.is_pat_binding_or_const) { 6 if !(ctx.is_trivial_path && !ctx.is_pat_binding_or_const && !ctx.record_lit_syntax.is_some()) {
7 return; 7 return;
8 } 8 }
9 9
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index fddaf21e4..eb8016dd1 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -1,13 +1,11 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{db::HirDatabase, Semantics, SemanticsScope}; 3use hir::{Semantics, SemanticsScope};
4use ra_db::SourceDatabase; 4use ra_db::SourceDatabase;
5use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::{ 6use ra_syntax::{
7 algo::{find_covering_element, find_node_at_offset}, 7 algo::{find_covering_element, find_node_at_offset},
8 ast, 8 ast, AstNode,
9 ast::ArgListOwner,
10 AstNode,
11 SyntaxKind::*, 9 SyntaxKind::*,
12 SyntaxNode, SyntaxToken, TextRange, TextUnit, 10 SyntaxNode, SyntaxToken, TextRange, TextUnit,
13}; 11};
@@ -196,7 +194,10 @@ impl<'a> CompletionContext<'a> {
196 if let Some(name) = find_node_at_offset::<ast::Name>(&file_with_fake_ident, offset) { 194 if let Some(name) = find_node_at_offset::<ast::Name>(&file_with_fake_ident, offset) {
197 if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) { 195 if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) {
198 self.is_pat_binding_or_const = true; 196 self.is_pat_binding_or_const = true;
199 if bind_pat.has_at() || bind_pat.is_ref() || bind_pat.is_mutable() { 197 if bind_pat.at_token().is_some()
198 || bind_pat.ref_token().is_some()
199 || bind_pat.mut_token().is_some()
200 {
200 self.is_pat_binding_or_const = false; 201 self.is_pat_binding_or_const = false;
201 } 202 }
202 if bind_pat.syntax().parent().and_then(ast::RecordFieldPatList::cast).is_some() { 203 if bind_pat.syntax().parent().and_then(ast::RecordFieldPatList::cast).is_some() {
@@ -230,7 +231,7 @@ impl<'a> CompletionContext<'a> {
230 self.name_ref_syntax = 231 self.name_ref_syntax =
231 find_node_at_offset(&original_file, name_ref.syntax().text_range().start()); 232 find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
232 let name_range = name_ref.syntax().text_range(); 233 let name_range = name_ref.syntax().text_range();
233 if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() { 234 if ast::RecordField::for_field_name(&name_ref).is_some() {
234 self.record_lit_syntax = 235 self.record_lit_syntax =
235 self.sema.find_node_at_offset_with_macros(&original_file, offset); 236 self.sema.find_node_at_offset_with_macros(&original_file, offset);
236 } 237 }
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs
index e58a78271..2d175882b 100644
--- a/crates/ra_ide/src/display/function_signature.rs
+++ b/crates/ra_ide/src/display/function_signature.rs
@@ -69,7 +69,13 @@ impl FunctionSignature {
69 for field in st.fields(db).into_iter() { 69 for field in st.fields(db).into_iter() {
70 let ty = field.signature_ty(db); 70 let ty = field.signature_ty(db);
71 let raw_param = format!("{}", ty.display(db)); 71 let raw_param = format!("{}", ty.display(db));
72 parameter_types.push(raw_param.split(':').nth(1).unwrap()[1..].to_string()); 72
73 if let Some(param_type) = raw_param.split(':').nth(1) {
74 parameter_types.push(param_type[1..].to_string());
75 } else {
76 // The unwrap_or_else is useful when you have tuple struct
77 parameter_types.push(raw_param.clone());
78 }
73 params.push(raw_param); 79 params.push(raw_param);
74 } 80 }
75 81
@@ -107,8 +113,15 @@ impl FunctionSignature {
107 for field in variant.fields(db).into_iter() { 113 for field in variant.fields(db).into_iter() {
108 let ty = field.signature_ty(db); 114 let ty = field.signature_ty(db);
109 let raw_param = format!("{}", ty.display(db)); 115 let raw_param = format!("{}", ty.display(db));
110 parameter_types.push(raw_param.split(':').nth(1).unwrap()[1..].to_string()); 116 if let Some(param_type) = raw_param.split(':').nth(1) {
111 params.push(raw_param); 117 parameter_types.push(param_type[1..].to_string());
118 } else {
119 // The unwrap_or_else is useful when you have tuple
120 parameter_types.push(raw_param);
121 }
122 let name = field.name(db);
123
124 params.push(format!("{}: {}", name, ty.display(db)));
112 } 125 }
113 126
114 Some( 127 Some(
@@ -164,7 +177,7 @@ impl From<&'_ ast::FnDef> for FunctionSignature {
164 has_self_param = true; 177 has_self_param = true;
165 let raw_param = self_param.syntax().text().to_string(); 178 let raw_param = self_param.syntax().text().to_string();
166 179
167 // TODO: better solution ? 180 // FIXME: better solution ?
168 res_types.push( 181 res_types.push(
169 raw_param.split(':').nth(1).unwrap_or_else(|| " Self")[1..].to_string(), 182 raw_param.split(':').nth(1).unwrap_or_else(|| " Self")[1..].to_string(),
170 ); 183 );
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 4b133b19b..45b9f7802 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! This module defines multiple types of inlay hints and their visibility
2 2
3use hir::{Adt, HirDisplay, Semantics, Type}; 3use hir::{Adt, HirDisplay, Semantics, Type};
4use ra_ide_db::RootDatabase; 4use ra_ide_db::RootDatabase;
@@ -235,8 +235,10 @@ fn should_show_param_hint(
235 param_name: &str, 235 param_name: &str,
236 argument: &ast::Expr, 236 argument: &ast::Expr,
237) -> bool { 237) -> bool {
238 let argument_string = argument.syntax().to_string(); 238 if param_name.is_empty()
239 if param_name.is_empty() || argument_string.ends_with(param_name) { 239 || is_argument_similar_to_param(argument, param_name)
240 || Some(param_name) == fn_signature.name.as_ref().map(String::as_str)
241 {
240 return false; 242 return false;
241 } 243 }
242 244
@@ -245,12 +247,32 @@ fn should_show_param_hint(
245 } else { 247 } else {
246 fn_signature.parameters.len() 248 fn_signature.parameters.len()
247 }; 249 };
250
248 // avoid displaying hints for common functions like map, filter, etc. 251 // avoid displaying hints for common functions like map, filter, etc.
249 if parameters_len == 1 && (param_name.len() == 1 || param_name == "predicate") { 252 // or other obvious words used in std
250 return false; 253 parameters_len != 1 || !is_obvious_param(param_name)
254}
255
256fn is_argument_similar_to_param(argument: &ast::Expr, param_name: &str) -> bool {
257 let argument_string = remove_ref(argument.clone()).syntax().to_string();
258 argument_string.starts_with(&param_name) || argument_string.ends_with(&param_name)
259}
260
261fn remove_ref(expr: ast::Expr) -> ast::Expr {
262 if let ast::Expr::RefExpr(ref_expr) = &expr {
263 if let Some(inner) = ref_expr.expr() {
264 return inner;
265 }
251 } 266 }
267 expr
268}
252 269
253 true 270fn is_obvious_param(param_name: &str) -> bool {
271 let is_obvious_param_name = match param_name {
272 "predicate" | "value" | "pat" | "rhs" | "other" => true,
273 _ => false,
274 };
275 param_name.len() == 1 || is_obvious_param_name
254} 276}
255 277
256fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<FunctionSignature> { 278fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<FunctionSignature> {
@@ -1059,9 +1081,22 @@ impl Test {
1059 self 1081 self
1060 } 1082 }
1061 1083
1084 fn field(self, value: i32) -> Self {
1085 self
1086 }
1087
1062 fn no_hints_expected(&self, _: i32, test_var: i32) {} 1088 fn no_hints_expected(&self, _: i32, test_var: i32) {}
1089
1090 fn frob(&self, frob: bool) {}
1063} 1091}
1064 1092
1093struct Param {}
1094
1095fn different_order(param: &Param) {}
1096fn different_order_mut(param: &mut Param) {}
1097
1098fn twiddle(twiddle: bool) {}
1099
1065fn main() { 1100fn main() {
1066 let container: TestVarContainer = TestVarContainer { test_var: 42 }; 1101 let container: TestVarContainer = TestVarContainer { test_var: 42 };
1067 let test: Test = Test {}; 1102 let test: Test = Test {};
@@ -1069,11 +1104,23 @@ fn main() {
1069 map(22); 1104 map(22);
1070 filter(33); 1105 filter(33);
1071 1106
1072 let test_processed: Test = test.map(1).filter(2); 1107 let test_processed: Test = test.map(1).filter(2).field(3);
1073 1108
1074 let test_var: i32 = 55; 1109 let test_var: i32 = 55;
1075 test_processed.no_hints_expected(22, test_var); 1110 test_processed.no_hints_expected(22, test_var);
1076 test_processed.no_hints_expected(33, container.test_var); 1111 test_processed.no_hints_expected(33, container.test_var);
1112 test_processed.frob(false);
1113
1114 twiddle(true);
1115
1116 let param_begin: Param = Param {};
1117 different_order(&param_begin);
1118 different_order(&mut param_begin);
1119
1120 let a: f64 = 7.0;
1121 let b: f64 = 4.0;
1122 let _: f64 = a.div_euclid(b);
1123 let _: f64 = a.abs_sub(b);
1077}"#, 1124}"#,
1078 ); 1125 );
1079 1126
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index 746cc86ba..7d0544ff4 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -152,7 +152,7 @@ fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Optio
152 if stmt.initializer().is_some() { 152 if stmt.initializer().is_some() {
153 let pat = stmt.pat()?; 153 let pat = stmt.pat()?;
154 if let ast::Pat::BindPat(it) = pat { 154 if let ast::Pat::BindPat(it) = pat {
155 if it.is_mutable() { 155 if it.mut_token().is_some() {
156 return Some(ReferenceAccess::Write); 156 return Some(ReferenceAccess::Write);
157 } 157 }
158 } 158 }
diff --git a/crates/ra_ide/src/syntax_tree.rs b/crates/ra_ide/src/syntax_tree.rs
index f58e436d1..5842ae2e8 100644
--- a/crates/ra_ide/src/syntax_tree.rs
+++ b/crates/ra_ide/src/syntax_tree.rs
@@ -165,7 +165,7 @@ SOURCE_FILE@[0; 60)
165 PATH_SEGMENT@[16; 22) 165 PATH_SEGMENT@[16; 22)
166 NAME_REF@[16; 22) 166 NAME_REF@[16; 22)
167 IDENT@[16; 22) "assert" 167 IDENT@[16; 22) "assert"
168 EXCL@[22; 23) "!" 168 BANG@[22; 23) "!"
169 TOKEN_TREE@[23; 57) 169 TOKEN_TREE@[23; 57)
170 L_PAREN@[23; 24) "(" 170 L_PAREN@[23; 24) "("
171 STRING@[24; 52) "\"\n fn foo() {\n ..." 171 STRING@[24; 52) "\"\n fn foo() {\n ..."
@@ -173,7 +173,7 @@ SOURCE_FILE@[0; 60)
173 WHITESPACE@[53; 54) " " 173 WHITESPACE@[53; 54) " "
174 STRING@[54; 56) "\"\"" 174 STRING@[54; 56) "\"\""
175 R_PAREN@[56; 57) ")" 175 R_PAREN@[56; 57) ")"
176 SEMI@[57; 58) ";" 176 SEMICOLON@[57; 58) ";"
177 WHITESPACE@[58; 59) "\n" 177 WHITESPACE@[58; 59) "\n"
178 R_CURLY@[59; 60) "}" 178 R_CURLY@[59; 60) "}"
179"# 179"#
@@ -226,7 +226,7 @@ EXPR_STMT@[16; 58)
226 PATH_SEGMENT@[16; 22) 226 PATH_SEGMENT@[16; 22)
227 NAME_REF@[16; 22) 227 NAME_REF@[16; 22)
228 IDENT@[16; 22) "assert" 228 IDENT@[16; 22) "assert"
229 EXCL@[22; 23) "!" 229 BANG@[22; 23) "!"
230 TOKEN_TREE@[23; 57) 230 TOKEN_TREE@[23; 57)
231 L_PAREN@[23; 24) "(" 231 L_PAREN@[23; 24) "("
232 STRING@[24; 52) "\"\n fn foo() {\n ..." 232 STRING@[24; 52) "\"\n fn foo() {\n ..."
@@ -234,7 +234,7 @@ EXPR_STMT@[16; 58)
234 WHITESPACE@[53; 54) " " 234 WHITESPACE@[53; 54) " "
235 STRING@[54; 56) "\"\"" 235 STRING@[54; 56) "\"\""
236 R_PAREN@[56; 57) ")" 236 R_PAREN@[56; 57) ")"
237 SEMI@[57; 58) ";" 237 SEMICOLON@[57; 58) ";"
238"# 238"#
239 .trim() 239 .trim()
240 ); 240 );
diff --git a/crates/ra_ide/src/typing.rs b/crates/ra_ide/src/typing.rs
index cb2cd2479..f55cd3bf5 100644
--- a/crates/ra_ide/src/typing.rs
+++ b/crates/ra_ide/src/typing.rs
@@ -63,7 +63,7 @@ fn on_char_typed_inner(
63fn on_eq_typed(file: &SourceFile, offset: TextUnit) -> Option<SingleFileChange> { 63fn on_eq_typed(file: &SourceFile, offset: TextUnit) -> Option<SingleFileChange> {
64 assert_eq!(file.syntax().text().char_at(offset), Some('=')); 64 assert_eq!(file.syntax().text().char_at(offset), Some('='));
65 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; 65 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
66 if let_stmt.has_semi() { 66 if let_stmt.semicolon_token().is_some() {
67 return None; 67 return None;
68 } 68 }
69 if let Some(expr) = let_stmt.initializer() { 69 if let Some(expr) = let_stmt.initializer() {
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs
index e9934844e..49a8c74fb 100644
--- a/crates/ra_ide_db/src/defs.rs
+++ b/crates/ra_ide_db/src/defs.rs
@@ -216,7 +216,7 @@ pub fn classify_name_ref(
216 } 216 }
217 } 217 }
218 218
219 if let Some(record_field) = ast::RecordField::cast(parent.clone()) { 219 if let Some(record_field) = ast::RecordField::for_field_name(name_ref) {
220 tested_by!(goto_def_for_record_fields; force); 220 tested_by!(goto_def_for_record_fields; force);
221 tested_by!(goto_def_for_field_init_shorthand; force); 221 tested_by!(goto_def_for_field_init_shorthand; force);
222 if let Some((field, local)) = sema.resolve_record_field(&record_field) { 222 if let Some((field, local)) = sema.resolve_record_field(&record_field) {
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 8e8ae2b29..9fb5cb058 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -137,21 +137,23 @@ impl TokenMap {
137 token_id: tt::TokenId, 137 token_id: tt::TokenId,
138 open_relative_range: TextRange, 138 open_relative_range: TextRange,
139 close_relative_range: TextRange, 139 close_relative_range: TextRange,
140 ) { 140 ) -> usize {
141 let res = self.entries.len();
141 self.entries 142 self.entries
142 .push((token_id, TokenTextRange::Delimiter(open_relative_range, close_relative_range))); 143 .push((token_id, TokenTextRange::Delimiter(open_relative_range, close_relative_range)));
144 res
143 } 145 }
144 146
145 fn update_close_delim(&mut self, token_id: tt::TokenId, close_relative_range: TextRange) { 147 fn update_close_delim(&mut self, idx: usize, close_relative_range: TextRange) {
146 if let Some(entry) = self.entries.iter_mut().find(|(tid, _)| *tid == token_id) { 148 let (_, token_text_range) = &mut self.entries[idx];
147 if let TokenTextRange::Delimiter(dim, _) = entry.1 { 149 if let TokenTextRange::Delimiter(dim, _) = token_text_range {
148 entry.1 = TokenTextRange::Delimiter(dim, close_relative_range); 150 *token_text_range = TokenTextRange::Delimiter(*dim, close_relative_range);
149 }
150 } 151 }
151 } 152 }
152 153
153 fn remove_delim(&mut self, token_id: tt::TokenId) { 154 fn remove_delim(&mut self, idx: usize) {
154 self.entries.retain(|(tid, _)| *tid != token_id); 155 // FIXME: This could be accidently quadratic
156 self.entries.remove(idx);
155 } 157 }
156} 158}
157 159
@@ -238,24 +240,24 @@ impl TokenIdAlloc {
238 token_id 240 token_id
239 } 241 }
240 242
241 fn open_delim(&mut self, open_abs_range: TextRange) -> tt::TokenId { 243 fn open_delim(&mut self, open_abs_range: TextRange) -> (tt::TokenId, usize) {
242 let token_id = tt::TokenId(self.next_id); 244 let token_id = tt::TokenId(self.next_id);
243 self.next_id += 1; 245 self.next_id += 1;
244 self.map.insert_delim( 246 let idx = self.map.insert_delim(
245 token_id, 247 token_id,
246 open_abs_range - self.global_offset, 248 open_abs_range - self.global_offset,
247 open_abs_range - self.global_offset, 249 open_abs_range - self.global_offset,
248 ); 250 );
249 token_id 251 (token_id, idx)
250 } 252 }
251 253
252 fn close_delim(&mut self, id: tt::TokenId, close_abs_range: Option<TextRange>) { 254 fn close_delim(&mut self, idx: usize, close_abs_range: Option<TextRange>) {
253 match close_abs_range { 255 match close_abs_range {
254 None => { 256 None => {
255 self.map.remove_delim(id); 257 self.map.remove_delim(idx);
256 } 258 }
257 Some(close) => { 259 Some(close) => {
258 self.map.update_close_delim(id, close - self.global_offset); 260 self.map.update_close_delim(idx, close - self.global_offset);
259 } 261 }
260 } 262 }
261 } 263 }
@@ -322,7 +324,7 @@ trait TokenConvertor {
322 324
323 if let Some((kind, closed)) = delim { 325 if let Some((kind, closed)) = delim {
324 let mut subtree = tt::Subtree::default(); 326 let mut subtree = tt::Subtree::default();
325 let id = self.id_alloc().open_delim(range); 327 let (id, idx) = self.id_alloc().open_delim(range);
326 subtree.delimiter = Some(tt::Delimiter { kind, id }); 328 subtree.delimiter = Some(tt::Delimiter { kind, id });
327 329
328 while self.peek().map(|it| it.kind() != closed).unwrap_or(false) { 330 while self.peek().map(|it| it.kind() != closed).unwrap_or(false) {
@@ -331,7 +333,7 @@ trait TokenConvertor {
331 let last_range = match self.bump() { 333 let last_range = match self.bump() {
332 None => { 334 None => {
333 // For error resilience, we insert an char punct for the opening delim here 335 // For error resilience, we insert an char punct for the opening delim here
334 self.id_alloc().close_delim(id, None); 336 self.id_alloc().close_delim(idx, None);
335 let leaf: tt::Leaf = tt::Punct { 337 let leaf: tt::Leaf = tt::Punct {
336 id: self.id_alloc().alloc(range), 338 id: self.id_alloc().alloc(range),
337 char: token.to_char().unwrap(), 339 char: token.to_char().unwrap(),
@@ -344,7 +346,7 @@ trait TokenConvertor {
344 } 346 }
345 Some(it) => it.1, 347 Some(it) => it.1,
346 }; 348 };
347 self.id_alloc().close_delim(id, Some(last_range)); 349 self.id_alloc().close_delim(idx, Some(last_range));
348 subtree.into() 350 subtree.into()
349 } else { 351 } else {
350 let spacing = match self.peek() { 352 let spacing = match self.peek() {
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
index 254318e23..5d1274d21 100644
--- a/crates/ra_mbe/src/tests.rs
+++ b/crates/ra_mbe/src/tests.rs
@@ -142,6 +142,79 @@ macro_rules! impl_froms {
142} 142}
143 143
144#[test] 144#[test]
145fn test_convert_tt2() {
146 parse_macro(
147 r#"
148macro_rules! impl_froms {
149 ($e:ident: $($v:ident),*) => {
150 $(
151 impl From<$v> for $e {
152 fn from(it: $v) -> $e {
153 $e::$v(it)
154 }
155 }
156 )*
157 }
158}
159"#,
160 )
161 .assert_expand(
162 "impl_froms!(TokenTree: Leaf, Subtree);",
163 r#"
164SUBTREE $
165 IDENT impl 20
166 IDENT From 21
167 PUNCH < [joint] 22
168 IDENT Leaf 53
169 PUNCH > [alone] 25
170 IDENT for 26
171 IDENT TokenTree 51
172 SUBTREE {} 29
173 IDENT fn 30
174 IDENT from 31
175 SUBTREE () 32
176 IDENT it 33
177 PUNCH : [alone] 34
178 IDENT Leaf 53
179 PUNCH - [joint] 37
180 PUNCH > [alone] 38
181 IDENT TokenTree 51
182 SUBTREE {} 41
183 IDENT TokenTree 51
184 PUNCH : [joint] 44
185 PUNCH : [joint] 45
186 IDENT Leaf 53
187 SUBTREE () 48
188 IDENT it 49
189 IDENT impl 20
190 IDENT From 21
191 PUNCH < [joint] 22
192 IDENT Subtree 55
193 PUNCH > [alone] 25
194 IDENT for 26
195 IDENT TokenTree 51
196 SUBTREE {} 29
197 IDENT fn 30
198 IDENT from 31
199 SUBTREE () 32
200 IDENT it 33
201 PUNCH : [alone] 34
202 IDENT Subtree 55
203 PUNCH - [joint] 37
204 PUNCH > [alone] 38
205 IDENT TokenTree 51
206 SUBTREE {} 41
207 IDENT TokenTree 51
208 PUNCH : [joint] 44
209 PUNCH : [joint] 45
210 IDENT Subtree 55
211 SUBTREE () 48
212 IDENT it 49
213"#,
214 );
215}
216
217#[test]
145fn test_expr_order() { 218fn test_expr_order() {
146 let expanded = parse_macro( 219 let expanded = parse_macro(
147 r#" 220 r#"
@@ -179,7 +252,7 @@ fn test_expr_order() {
179 STAR@[11; 12) "*" 252 STAR@[11; 12) "*"
180 LITERAL@[12; 13) 253 LITERAL@[12; 13)
181 INT_NUMBER@[12; 13) "2" 254 INT_NUMBER@[12; 13) "2"
182 SEMI@[13; 14) ";" 255 SEMICOLON@[13; 14) ";"
183 R_CURLY@[14; 15) "}""#, 256 R_CURLY@[14; 15) "}""#,
184 ); 257 );
185} 258}
@@ -532,7 +605,7 @@ fn test_tt_to_stmts() {
532 EQ@[4; 5) "=" 605 EQ@[4; 5) "="
533 LITERAL@[5; 6) 606 LITERAL@[5; 6)
534 INT_NUMBER@[5; 6) "0" 607 INT_NUMBER@[5; 6) "0"
535 SEMI@[6; 7) ";" 608 SEMICOLON@[6; 7) ";"
536 EXPR_STMT@[7; 14) 609 EXPR_STMT@[7; 14)
537 BIN_EXPR@[7; 13) 610 BIN_EXPR@[7; 13)
538 PATH_EXPR@[7; 8) 611 PATH_EXPR@[7; 8)
@@ -547,7 +620,7 @@ fn test_tt_to_stmts() {
547 PLUS@[11; 12) "+" 620 PLUS@[11; 12) "+"
548 LITERAL@[12; 13) 621 LITERAL@[12; 13)
549 INT_NUMBER@[12; 13) "1" 622 INT_NUMBER@[12; 13) "1"
550 SEMI@[13; 14) ";" 623 SEMICOLON@[13; 14) ";"
551 EXPR_STMT@[14; 15) 624 EXPR_STMT@[14; 15)
552 PATH_EXPR@[14; 15) 625 PATH_EXPR@[14; 15)
553 PATH@[14; 15) 626 PATH@[14; 15)
@@ -880,7 +953,7 @@ fn test_tt_composite2() {
880 PATH_SEGMENT@[0; 3) 953 PATH_SEGMENT@[0; 3)
881 NAME_REF@[0; 3) 954 NAME_REF@[0; 3)
882 IDENT@[0; 3) "abs" 955 IDENT@[0; 3) "abs"
883 EXCL@[3; 4) "!" 956 BANG@[3; 4) "!"
884 TOKEN_TREE@[4; 10) 957 TOKEN_TREE@[4; 10)
885 L_PAREN@[4; 5) "(" 958 L_PAREN@[4; 5) "("
886 EQ@[5; 6) "=" 959 EQ@[5; 6) "="
@@ -1000,14 +1073,14 @@ fn test_vec() {
1000 PATH_SEGMENT@[9; 12) 1073 PATH_SEGMENT@[9; 12)
1001 NAME_REF@[9; 12) 1074 NAME_REF@[9; 12)
1002 IDENT@[9; 12) "Vec" 1075 IDENT@[9; 12) "Vec"
1003 COLONCOLON@[12; 14) "::" 1076 COLON2@[12; 14) "::"
1004 PATH_SEGMENT@[14; 17) 1077 PATH_SEGMENT@[14; 17)
1005 NAME_REF@[14; 17) 1078 NAME_REF@[14; 17)
1006 IDENT@[14; 17) "new" 1079 IDENT@[14; 17) "new"
1007 ARG_LIST@[17; 19) 1080 ARG_LIST@[17; 19)
1008 L_PAREN@[17; 18) "(" 1081 L_PAREN@[17; 18) "("
1009 R_PAREN@[18; 19) ")" 1082 R_PAREN@[18; 19) ")"
1010 SEMI@[19; 20) ";" 1083 SEMICOLON@[19; 20) ";"
1011 EXPR_STMT@[20; 33) 1084 EXPR_STMT@[20; 33)
1012 METHOD_CALL_EXPR@[20; 32) 1085 METHOD_CALL_EXPR@[20; 32)
1013 PATH_EXPR@[20; 21) 1086 PATH_EXPR@[20; 21)
@@ -1023,7 +1096,7 @@ fn test_vec() {
1023 LITERAL@[27; 31) 1096 LITERAL@[27; 31)
1024 INT_NUMBER@[27; 31) "1u32" 1097 INT_NUMBER@[27; 31) "1u32"
1025 R_PAREN@[31; 32) ")" 1098 R_PAREN@[31; 32) ")"
1026 SEMI@[32; 33) ";" 1099 SEMICOLON@[32; 33) ";"
1027 EXPR_STMT@[33; 43) 1100 EXPR_STMT@[33; 43)
1028 METHOD_CALL_EXPR@[33; 42) 1101 METHOD_CALL_EXPR@[33; 42)
1029 PATH_EXPR@[33; 34) 1102 PATH_EXPR@[33; 34)
@@ -1039,7 +1112,7 @@ fn test_vec() {
1039 LITERAL@[40; 41) 1112 LITERAL@[40; 41)
1040 INT_NUMBER@[40; 41) "2" 1113 INT_NUMBER@[40; 41) "2"
1041 R_PAREN@[41; 42) ")" 1114 R_PAREN@[41; 42) ")"
1042 SEMI@[42; 43) ";" 1115 SEMICOLON@[42; 43) ";"
1043 PATH_EXPR@[43; 44) 1116 PATH_EXPR@[43; 44)
1044 PATH@[43; 44) 1117 PATH@[43; 44)
1045 PATH_SEGMENT@[43; 44) 1118 PATH_SEGMENT@[43; 44)
@@ -1479,6 +1552,12 @@ impl MacroFixture {
1479 assert_eq!(expansion.to_string(), expected); 1552 assert_eq!(expansion.to_string(), expected);
1480 } 1553 }
1481 1554
1555 fn assert_expand(&self, invocation: &str, expected: &str) {
1556 let expansion = self.expand_tt(invocation);
1557 let actual = format!("{:?}", expansion);
1558 test_utils::assert_eq_text!(&actual.trim(), &expected.trim());
1559 }
1560
1482 fn assert_expand_items(&self, invocation: &str, expected: &str) -> &MacroFixture { 1561 fn assert_expand_items(&self, invocation: &str, expected: &str) -> &MacroFixture {
1483 self.assert_expansion(FragmentKind::Items, invocation, expected); 1562 self.assert_expansion(FragmentKind::Items, invocation, expected);
1484 self 1563 self
@@ -1681,7 +1760,7 @@ fn test_no_space_after_semi_colon() {
1681 MOD_KW@[21; 24) "mod" 1760 MOD_KW@[21; 24) "mod"
1682 NAME@[24; 25) 1761 NAME@[24; 25)
1683 IDENT@[24; 25) "m" 1762 IDENT@[24; 25) "m"
1684 SEMI@[25; 26) ";" 1763 SEMICOLON@[25; 26) ";"
1685 MODULE@[26; 52) 1764 MODULE@[26; 52)
1686 ATTR@[26; 47) 1765 ATTR@[26; 47)
1687 POUND@[26; 27) "#" 1766 POUND@[26; 27) "#"
@@ -1700,7 +1779,7 @@ fn test_no_space_after_semi_colon() {
1700 MOD_KW@[47; 50) "mod" 1779 MOD_KW@[47; 50) "mod"
1701 NAME@[50; 51) 1780 NAME@[50; 51)
1702 IDENT@[50; 51) "f" 1781 IDENT@[50; 51) "f"
1703 SEMI@[51; 52) ";""###, 1782 SEMICOLON@[51; 52) ";""###,
1704 ); 1783 );
1705} 1784}
1706 1785
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index c486c0211..cb30b25a8 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -339,7 +339,8 @@ fn expr_bp(p: &mut Parser, mut r: Restrictions, bp: u8) -> (Option<CompletedMark
339 (Some(lhs), BlockLike::NotBlock) 339 (Some(lhs), BlockLike::NotBlock)
340} 340}
341 341
342const LHS_FIRST: TokenSet = atom::ATOM_EXPR_FIRST.union(token_set![AMP, STAR, EXCL, DOT, MINUS]); 342const LHS_FIRST: TokenSet =
343 atom::ATOM_EXPR_FIRST.union(token_set![T![&], T![*], T![!], T![.], T![-]]);
343 344
344fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> { 345fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
345 let m; 346 let m;
@@ -618,26 +619,39 @@ pub(crate) fn record_field_list(p: &mut Parser) {
618 let m = p.start(); 619 let m = p.start();
619 p.bump(T!['{']); 620 p.bump(T!['{']);
620 while !p.at(EOF) && !p.at(T!['}']) { 621 while !p.at(EOF) && !p.at(T!['}']) {
622 let m = p.start();
623 // test record_literal_field_with_attr
624 // fn main() {
625 // S { #[cfg(test)] field: 1 }
626 // }
627 attributes::outer_attributes(p);
628
621 match p.current() { 629 match p.current() {
622 // test record_literal_field_with_attr 630 IDENT | INT_NUMBER => {
623 // fn main() { 631 // test_err record_literal_before_ellipsis_recovery
624 // S { #[cfg(test)] field: 1 } 632 // fn main() {
625 // } 633 // S { field ..S::default() }
626 IDENT | INT_NUMBER | T![#] => { 634 // }
627 let m = p.start(); 635 if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) {
628 attributes::outer_attributes(p); 636 name_ref_or_index(p);
629 name_ref_or_index(p); 637 p.expect(T![:]);
630 if p.eat(T![:]) {
631 expr(p);
632 } 638 }
639 expr(p);
633 m.complete(p, RECORD_FIELD); 640 m.complete(p, RECORD_FIELD);
634 } 641 }
635 T![.] if p.at(T![..]) => { 642 T![.] if p.at(T![..]) => {
643 m.abandon(p);
636 p.bump(T![..]); 644 p.bump(T![..]);
637 expr(p); 645 expr(p);
638 } 646 }
639 T!['{'] => error_block(p, "expected a field"), 647 T!['{'] => {
640 _ => p.err_and_bump("expected identifier"), 648 error_block(p, "expected a field");
649 m.abandon(p);
650 }
651 _ => {
652 p.err_and_bump("expected identifier");
653 m.abandon(p);
654 }
641 } 655 }
642 if !p.at(T!['}']) { 656 if !p.at(T!['}']) {
643 p.expect(T![,]); 657 p.expect(T![,]);
diff --git a/crates/ra_parser/src/grammar/types.rs b/crates/ra_parser/src/grammar/types.rs
index 386969d2d..fe1a039cb 100644
--- a/crates/ra_parser/src/grammar/types.rs
+++ b/crates/ra_parser/src/grammar/types.rs
@@ -3,8 +3,19 @@
3use super::*; 3use super::*;
4 4
5pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(token_set![ 5pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(token_set![
6 L_PAREN, EXCL, STAR, L_BRACK, AMP, UNDERSCORE, FN_KW, UNSAFE_KW, EXTERN_KW, FOR_KW, IMPL_KW, 6 T!['('],
7 DYN_KW, L_ANGLE, 7 T!['['],
8 T![<],
9 T![!],
10 T![*],
11 T![&],
12 T![_],
13 T![fn],
14 T![unsafe],
15 T![extern],
16 T![for],
17 T![impl],
18 T![dyn],
8]); 19]);
9 20
10const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA, L_DOLLAR]; 21const TYPE_RECOVERY_SET: TokenSet = token_set![R_PAREN, COMMA, L_DOLLAR];
diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs
index 004f4e564..524e7d784 100644
--- a/crates/ra_parser/src/syntax_kind/generated.rs
+++ b/crates/ra_parser/src/syntax_kind/generated.rs
@@ -9,7 +9,7 @@ pub enum SyntaxKind {
9 TOMBSTONE, 9 TOMBSTONE,
10 #[doc(hidden)] 10 #[doc(hidden)]
11 EOF, 11 EOF,
12 SEMI, 12 SEMICOLON,
13 COMMA, 13 COMMA,
14 L_PAREN, 14 L_PAREN,
15 R_PAREN, 15 R_PAREN,
@@ -33,15 +33,15 @@ pub enum SyntaxKind {
33 PERCENT, 33 PERCENT,
34 UNDERSCORE, 34 UNDERSCORE,
35 DOT, 35 DOT,
36 DOTDOT, 36 DOT2,
37 DOTDOTDOT, 37 DOT3,
38 DOTDOTEQ, 38 DOT2EQ,
39 COLON, 39 COLON,
40 COLONCOLON, 40 COLON2,
41 EQ, 41 EQ,
42 EQEQ, 42 EQ2,
43 FAT_ARROW, 43 FAT_ARROW,
44 EXCL, 44 BANG,
45 NEQ, 45 NEQ,
46 MINUS, 46 MINUS,
47 THIN_ARROW, 47 THIN_ARROW,
@@ -55,8 +55,8 @@ pub enum SyntaxKind {
55 SLASHEQ, 55 SLASHEQ,
56 STAREQ, 56 STAREQ,
57 PERCENTEQ, 57 PERCENTEQ,
58 AMPAMP, 58 AMP2,
59 PIPEPIPE, 59 PIPE2,
60 SHL, 60 SHL,
61 SHR, 61 SHR,
62 SHLEQ, 62 SHLEQ,
@@ -265,12 +265,12 @@ impl SyntaxKind {
265 } 265 }
266 pub fn is_punct(self) -> bool { 266 pub fn is_punct(self) -> bool {
267 match self { 267 match self {
268 SEMI | COMMA | L_PAREN | R_PAREN | L_CURLY | R_CURLY | L_BRACK | R_BRACK | L_ANGLE 268 SEMICOLON | COMMA | L_PAREN | R_PAREN | L_CURLY | R_CURLY | L_BRACK | R_BRACK
269 | R_ANGLE | AT | POUND | TILDE | QUESTION | DOLLAR | AMP | PIPE | PLUS | STAR 269 | L_ANGLE | R_ANGLE | AT | POUND | TILDE | QUESTION | DOLLAR | AMP | PIPE | PLUS
270 | SLASH | CARET | PERCENT | UNDERSCORE | DOT | DOTDOT | DOTDOTDOT | DOTDOTEQ 270 | STAR | SLASH | CARET | PERCENT | UNDERSCORE | DOT | DOT2 | DOT3 | DOT2EQ | COLON
271 | COLON | COLONCOLON | EQ | EQEQ | FAT_ARROW | EXCL | NEQ | MINUS | THIN_ARROW 271 | COLON2 | EQ | EQ2 | FAT_ARROW | BANG | NEQ | MINUS | THIN_ARROW | LTEQ | GTEQ
272 | LTEQ | GTEQ | PLUSEQ | MINUSEQ | PIPEEQ | AMPEQ | CARETEQ | SLASHEQ | STAREQ 272 | PLUSEQ | MINUSEQ | PIPEEQ | AMPEQ | CARETEQ | SLASHEQ | STAREQ | PERCENTEQ | AMP2
273 | PERCENTEQ | AMPAMP | PIPEPIPE | SHL | SHR | SHLEQ | SHREQ => true, 273 | PIPE2 | SHL | SHR | SHLEQ | SHREQ => true,
274 _ => false, 274 _ => false,
275 } 275 }
276 } 276 }
@@ -329,7 +329,7 @@ impl SyntaxKind {
329 } 329 }
330 pub fn from_char(c: char) -> Option<SyntaxKind> { 330 pub fn from_char(c: char) -> Option<SyntaxKind> {
331 let tok = match c { 331 let tok = match c {
332 ';' => SEMI, 332 ';' => SEMICOLON,
333 ',' => COMMA, 333 ',' => COMMA,
334 '(' => L_PAREN, 334 '(' => L_PAREN,
335 ')' => R_PAREN, 335 ')' => R_PAREN,
@@ -355,7 +355,7 @@ impl SyntaxKind {
355 '.' => DOT, 355 '.' => DOT,
356 ':' => COLON, 356 ':' => COLON,
357 '=' => EQ, 357 '=' => EQ,
358 '!' => EXCL, 358 '!' => BANG,
359 '-' => MINUS, 359 '-' => MINUS,
360 _ => return None, 360 _ => return None,
361 }; 361 };
@@ -363,296 +363,4 @@ impl SyntaxKind {
363 } 363 }
364} 364}
365#[macro_export] 365#[macro_export]
366macro_rules! T { 366macro_rules ! T { [ ; ] => { $ crate :: SyntaxKind :: SEMICOLON } ; [ , ] => { $ crate :: SyntaxKind :: COMMA } ; [ '(' ] => { $ crate :: SyntaxKind :: L_PAREN } ; [ ')' ] => { $ crate :: SyntaxKind :: R_PAREN } ; [ '{' ] => { $ crate :: SyntaxKind :: L_CURLY } ; [ '}' ] => { $ crate :: SyntaxKind :: R_CURLY } ; [ '[' ] => { $ crate :: SyntaxKind :: L_BRACK } ; [ ']' ] => { $ crate :: SyntaxKind :: R_BRACK } ; [ < ] => { $ crate :: SyntaxKind :: L_ANGLE } ; [ > ] => { $ crate :: SyntaxKind :: R_ANGLE } ; [ @ ] => { $ crate :: SyntaxKind :: AT } ; [ # ] => { $ crate :: SyntaxKind :: POUND } ; [ ~ ] => { $ crate :: SyntaxKind :: TILDE } ; [ ? ] => { $ crate :: SyntaxKind :: QUESTION } ; [ $ ] => { $ crate :: SyntaxKind :: DOLLAR } ; [ & ] => { $ crate :: SyntaxKind :: AMP } ; [ | ] => { $ crate :: SyntaxKind :: PIPE } ; [ + ] => { $ crate :: SyntaxKind :: PLUS } ; [ * ] => { $ crate :: SyntaxKind :: STAR } ; [ / ] => { $ crate :: SyntaxKind :: SLASH } ; [ ^ ] => { $ crate :: SyntaxKind :: CARET } ; [ % ] => { $ crate :: SyntaxKind :: PERCENT } ; [ _ ] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [ . ] => { $ crate :: SyntaxKind :: DOT } ; [ .. ] => { $ crate :: SyntaxKind :: DOT2 } ; [ ... ] => { $ crate :: SyntaxKind :: DOT3 } ; [ ..= ] => { $ crate :: SyntaxKind :: DOT2EQ } ; [ : ] => { $ crate :: SyntaxKind :: COLON } ; [ :: ] => { $ crate :: SyntaxKind :: COLON2 } ; [ = ] => { $ crate :: SyntaxKind :: EQ } ; [ == ] => { $ crate :: SyntaxKind :: EQ2 } ; [ => ] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [ ! ] => { $ crate :: SyntaxKind :: BANG } ; [ != ] => { $ crate :: SyntaxKind :: NEQ } ; [ - ] => { $ crate :: SyntaxKind :: MINUS } ; [ -> ] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [ <= ] => { $ crate :: SyntaxKind :: LTEQ } ; [ >= ] => { $ crate :: SyntaxKind :: GTEQ } ; [ += ] => { $ crate :: SyntaxKind :: PLUSEQ } ; [ -= ] => { $ crate :: SyntaxKind :: MINUSEQ } ; [ |= ] => { $ crate :: SyntaxKind :: PIPEEQ } ; [ &= ] => { $ crate :: SyntaxKind :: AMPEQ } ; [ ^= ] => { $ crate :: SyntaxKind :: CARETEQ } ; [ /= ] => { $ crate :: SyntaxKind :: SLASHEQ } ; [ *= ] => { $ crate :: SyntaxKind :: STAREQ } ; [ %= ] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [ && ] => { $ crate :: SyntaxKind :: AMP2 } ; [ || ] => { $ crate :: SyntaxKind :: PIPE2 } ; [ << ] => { $ crate :: SyntaxKind :: SHL } ; [ >> ] => { $ crate :: SyntaxKind :: SHR } ; [ <<= ] => { $ crate :: SyntaxKind :: SHLEQ } ; [ >>= ] => { $ crate :: SyntaxKind :: SHREQ } ; [ as ] => { $ crate :: SyntaxKind :: AS_KW } ; [ async ] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [ await ] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [ box ] => { $ crate :: SyntaxKind :: BOX_KW } ; [ break ] => { $ crate :: SyntaxKind :: BREAK_KW } ; [ const ] => { $ crate :: SyntaxKind :: CONST_KW } ; [ continue ] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [ crate ] => { $ crate :: SyntaxKind :: CRATE_KW } ; [ dyn ] => { $ crate :: SyntaxKind :: DYN_KW } ; [ else ] => { $ crate :: SyntaxKind :: ELSE_KW } ; [ enum ] => { $ crate :: SyntaxKind :: ENUM_KW } ; [ extern ] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [ false ] => { $ crate :: SyntaxKind :: FALSE_KW } ; [ fn ] => { $ crate :: SyntaxKind :: FN_KW } ; [ for ] => { $ crate :: SyntaxKind :: FOR_KW } ; [ if ] => { $ crate :: SyntaxKind :: IF_KW } ; [ impl ] => { $ crate :: SyntaxKind :: IMPL_KW } ; [ in ] => { $ crate :: SyntaxKind :: IN_KW } ; [ let ] => { $ crate :: SyntaxKind :: LET_KW } ; [ loop ] => { $ crate :: SyntaxKind :: LOOP_KW } ; [ macro ] => { $ crate :: SyntaxKind :: MACRO_KW } ; [ match ] => { $ crate :: SyntaxKind :: MATCH_KW } ; [ mod ] => { $ crate :: SyntaxKind :: MOD_KW } ; [ move ] => { $ crate :: SyntaxKind :: MOVE_KW } ; [ mut ] => { $ crate :: SyntaxKind :: MUT_KW } ; [ pub ] => { $ crate :: SyntaxKind :: PUB_KW } ; [ ref ] => { $ crate :: SyntaxKind :: REF_KW } ; [ return ] => { $ crate :: SyntaxKind :: RETURN_KW } ; [ self ] => { $ crate :: SyntaxKind :: SELF_KW } ; [ static ] => { $ crate :: SyntaxKind :: STATIC_KW } ; [ struct ] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [ super ] => { $ crate :: SyntaxKind :: SUPER_KW } ; [ trait ] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [ true ] => { $ crate :: SyntaxKind :: TRUE_KW } ; [ try ] => { $ crate :: SyntaxKind :: TRY_KW } ; [ type ] => { $ crate :: SyntaxKind :: TYPE_KW } ; [ unsafe ] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [ use ] => { $ crate :: SyntaxKind :: USE_KW } ; [ where ] => { $ crate :: SyntaxKind :: WHERE_KW } ; [ while ] => { $ crate :: SyntaxKind :: WHILE_KW } ; [ auto ] => { $ crate :: SyntaxKind :: AUTO_KW } ; [ default ] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [ existential ] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [ union ] => { $ crate :: SyntaxKind :: UNION_KW } ; [ raw ] => { $ crate :: SyntaxKind :: RAW_KW } ; [ lifetime ] => { $ crate :: SyntaxKind :: LIFETIME } ; [ ident ] => { $ crate :: SyntaxKind :: IDENT } ; }
367 ( ; ) => {
368 $crate::SyntaxKind::SEMI
369 };
370 ( , ) => {
371 $crate::SyntaxKind::COMMA
372 };
373 ( '(' ) => {
374 $crate::SyntaxKind::L_PAREN
375 };
376 ( ')' ) => {
377 $crate::SyntaxKind::R_PAREN
378 };
379 ( '{' ) => {
380 $crate::SyntaxKind::L_CURLY
381 };
382 ( '}' ) => {
383 $crate::SyntaxKind::R_CURLY
384 };
385 ( '[' ) => {
386 $crate::SyntaxKind::L_BRACK
387 };
388 ( ']' ) => {
389 $crate::SyntaxKind::R_BRACK
390 };
391 ( < ) => {
392 $crate::SyntaxKind::L_ANGLE
393 };
394 ( > ) => {
395 $crate::SyntaxKind::R_ANGLE
396 };
397 ( @ ) => {
398 $crate::SyntaxKind::AT
399 };
400 ( # ) => {
401 $crate::SyntaxKind::POUND
402 };
403 ( ~ ) => {
404 $crate::SyntaxKind::TILDE
405 };
406 ( ? ) => {
407 $crate::SyntaxKind::QUESTION
408 };
409 ( $ ) => {
410 $crate::SyntaxKind::DOLLAR
411 };
412 ( & ) => {
413 $crate::SyntaxKind::AMP
414 };
415 ( | ) => {
416 $crate::SyntaxKind::PIPE
417 };
418 ( + ) => {
419 $crate::SyntaxKind::PLUS
420 };
421 ( * ) => {
422 $crate::SyntaxKind::STAR
423 };
424 ( / ) => {
425 $crate::SyntaxKind::SLASH
426 };
427 ( ^ ) => {
428 $crate::SyntaxKind::CARET
429 };
430 ( % ) => {
431 $crate::SyntaxKind::PERCENT
432 };
433 ( _ ) => {
434 $crate::SyntaxKind::UNDERSCORE
435 };
436 ( . ) => {
437 $crate::SyntaxKind::DOT
438 };
439 ( .. ) => {
440 $crate::SyntaxKind::DOTDOT
441 };
442 ( ... ) => {
443 $crate::SyntaxKind::DOTDOTDOT
444 };
445 ( ..= ) => {
446 $crate::SyntaxKind::DOTDOTEQ
447 };
448 ( : ) => {
449 $crate::SyntaxKind::COLON
450 };
451 ( :: ) => {
452 $crate::SyntaxKind::COLONCOLON
453 };
454 ( = ) => {
455 $crate::SyntaxKind::EQ
456 };
457 ( == ) => {
458 $crate::SyntaxKind::EQEQ
459 };
460 ( => ) => {
461 $crate::SyntaxKind::FAT_ARROW
462 };
463 ( ! ) => {
464 $crate::SyntaxKind::EXCL
465 };
466 ( != ) => {
467 $crate::SyntaxKind::NEQ
468 };
469 ( - ) => {
470 $crate::SyntaxKind::MINUS
471 };
472 ( -> ) => {
473 $crate::SyntaxKind::THIN_ARROW
474 };
475 ( <= ) => {
476 $crate::SyntaxKind::LTEQ
477 };
478 ( >= ) => {
479 $crate::SyntaxKind::GTEQ
480 };
481 ( += ) => {
482 $crate::SyntaxKind::PLUSEQ
483 };
484 ( -= ) => {
485 $crate::SyntaxKind::MINUSEQ
486 };
487 ( |= ) => {
488 $crate::SyntaxKind::PIPEEQ
489 };
490 ( &= ) => {
491 $crate::SyntaxKind::AMPEQ
492 };
493 ( ^= ) => {
494 $crate::SyntaxKind::CARETEQ
495 };
496 ( /= ) => {
497 $crate::SyntaxKind::SLASHEQ
498 };
499 ( *= ) => {
500 $crate::SyntaxKind::STAREQ
501 };
502 ( %= ) => {
503 $crate::SyntaxKind::PERCENTEQ
504 };
505 ( && ) => {
506 $crate::SyntaxKind::AMPAMP
507 };
508 ( || ) => {
509 $crate::SyntaxKind::PIPEPIPE
510 };
511 ( << ) => {
512 $crate::SyntaxKind::SHL
513 };
514 ( >> ) => {
515 $crate::SyntaxKind::SHR
516 };
517 ( <<= ) => {
518 $crate::SyntaxKind::SHLEQ
519 };
520 ( >>= ) => {
521 $crate::SyntaxKind::SHREQ
522 };
523 ( as ) => {
524 $crate::SyntaxKind::AS_KW
525 };
526 ( async ) => {
527 $crate::SyntaxKind::ASYNC_KW
528 };
529 ( await ) => {
530 $crate::SyntaxKind::AWAIT_KW
531 };
532 ( box ) => {
533 $crate::SyntaxKind::BOX_KW
534 };
535 ( break ) => {
536 $crate::SyntaxKind::BREAK_KW
537 };
538 ( const ) => {
539 $crate::SyntaxKind::CONST_KW
540 };
541 ( continue ) => {
542 $crate::SyntaxKind::CONTINUE_KW
543 };
544 ( crate ) => {
545 $crate::SyntaxKind::CRATE_KW
546 };
547 ( dyn ) => {
548 $crate::SyntaxKind::DYN_KW
549 };
550 ( else ) => {
551 $crate::SyntaxKind::ELSE_KW
552 };
553 ( enum ) => {
554 $crate::SyntaxKind::ENUM_KW
555 };
556 ( extern ) => {
557 $crate::SyntaxKind::EXTERN_KW
558 };
559 ( false ) => {
560 $crate::SyntaxKind::FALSE_KW
561 };
562 ( fn ) => {
563 $crate::SyntaxKind::FN_KW
564 };
565 ( for ) => {
566 $crate::SyntaxKind::FOR_KW
567 };
568 ( if ) => {
569 $crate::SyntaxKind::IF_KW
570 };
571 ( impl ) => {
572 $crate::SyntaxKind::IMPL_KW
573 };
574 ( in ) => {
575 $crate::SyntaxKind::IN_KW
576 };
577 ( let ) => {
578 $crate::SyntaxKind::LET_KW
579 };
580 ( loop ) => {
581 $crate::SyntaxKind::LOOP_KW
582 };
583 ( macro ) => {
584 $crate::SyntaxKind::MACRO_KW
585 };
586 ( match ) => {
587 $crate::SyntaxKind::MATCH_KW
588 };
589 ( mod ) => {
590 $crate::SyntaxKind::MOD_KW
591 };
592 ( move ) => {
593 $crate::SyntaxKind::MOVE_KW
594 };
595 ( mut ) => {
596 $crate::SyntaxKind::MUT_KW
597 };
598 ( pub ) => {
599 $crate::SyntaxKind::PUB_KW
600 };
601 ( ref ) => {
602 $crate::SyntaxKind::REF_KW
603 };
604 ( return ) => {
605 $crate::SyntaxKind::RETURN_KW
606 };
607 ( self ) => {
608 $crate::SyntaxKind::SELF_KW
609 };
610 ( static ) => {
611 $crate::SyntaxKind::STATIC_KW
612 };
613 ( struct ) => {
614 $crate::SyntaxKind::STRUCT_KW
615 };
616 ( super ) => {
617 $crate::SyntaxKind::SUPER_KW
618 };
619 ( trait ) => {
620 $crate::SyntaxKind::TRAIT_KW
621 };
622 ( true ) => {
623 $crate::SyntaxKind::TRUE_KW
624 };
625 ( try ) => {
626 $crate::SyntaxKind::TRY_KW
627 };
628 ( type ) => {
629 $crate::SyntaxKind::TYPE_KW
630 };
631 ( unsafe ) => {
632 $crate::SyntaxKind::UNSAFE_KW
633 };
634 ( use ) => {
635 $crate::SyntaxKind::USE_KW
636 };
637 ( where ) => {
638 $crate::SyntaxKind::WHERE_KW
639 };
640 ( while ) => {
641 $crate::SyntaxKind::WHILE_KW
642 };
643 ( auto ) => {
644 $crate::SyntaxKind::AUTO_KW
645 };
646 ( default ) => {
647 $crate::SyntaxKind::DEFAULT_KW
648 };
649 ( existential ) => {
650 $crate::SyntaxKind::EXISTENTIAL_KW
651 };
652 ( union ) => {
653 $crate::SyntaxKind::UNION_KW
654 };
655 ( raw ) => {
656 $crate::SyntaxKind::RAW_KW
657 };
658}
diff --git a/crates/ra_proc_macro_srv/Cargo.toml b/crates/ra_proc_macro_srv/Cargo.toml
index f08de5fc7..1e0f50339 100644
--- a/crates/ra_proc_macro_srv/Cargo.toml
+++ b/crates/ra_proc_macro_srv/Cargo.toml
@@ -12,9 +12,12 @@ doctest = false
12ra_tt = { path = "../ra_tt" } 12ra_tt = { path = "../ra_tt" }
13ra_mbe = { path = "../ra_mbe" } 13ra_mbe = { path = "../ra_mbe" }
14ra_proc_macro = { path = "../ra_proc_macro" } 14ra_proc_macro = { path = "../ra_proc_macro" }
15goblin = "0.2.1"
16libloading = "0.6.0"
17test_utils = { path = "../test_utils" }
15 18
16[dev-dependencies] 19[dev-dependencies]
17cargo_metadata = "0.9.1" 20cargo_metadata = "0.9.1"
18difference = "2.0.0" 21difference = "2.0.0"
19# used as proc macro test target 22# used as proc macro test target
20serde_derive = "=1.0.104" \ No newline at end of file 23serde_derive = "=1.0.104"
diff --git a/crates/ra_proc_macro_srv/src/dylib.rs b/crates/ra_proc_macro_srv/src/dylib.rs
new file mode 100644
index 000000000..ec63d587b
--- /dev/null
+++ b/crates/ra_proc_macro_srv/src/dylib.rs
@@ -0,0 +1,211 @@
1//! Handles dynamic library loading for proc macro
2
3use crate::{proc_macro::bridge, rustc_server::TokenStream};
4use std::path::Path;
5
6use goblin::{mach::Mach, Object};
7use libloading::Library;
8use ra_proc_macro::ProcMacroKind;
9
10use std::io::Error as IoError;
11use std::io::ErrorKind as IoErrorKind;
12
13const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_";
14
15fn invalid_data_err(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> IoError {
16 IoError::new(IoErrorKind::InvalidData, e)
17}
18
19fn get_symbols_from_lib(file: &Path) -> Result<Vec<String>, IoError> {
20 let buffer = std::fs::read(file)?;
21 let object = Object::parse(&buffer).map_err(invalid_data_err)?;
22
23 match object {
24 Object::Elf(elf) => {
25 let symbols = elf.dynstrtab.to_vec().map_err(invalid_data_err)?;
26 let names = symbols.iter().map(|s| s.to_string()).collect();
27 Ok(names)
28 }
29 Object::PE(pe) => {
30 let symbol_names =
31 pe.exports.iter().flat_map(|s| s.name).map(|n| n.to_string()).collect();
32 Ok(symbol_names)
33 }
34 Object::Mach(mach) => match mach {
35 Mach::Binary(binary) => {
36 let exports = binary.exports().map_err(invalid_data_err)?;
37 let names = exports
38 .into_iter()
39 .map(|s| {
40 // In macos doc:
41 // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html
42 // Unlike other dyld API's, the symbol name passed to dlsym() must NOT be
43 // prepended with an underscore.
44 if s.name.starts_with("_") {
45 s.name[1..].to_string()
46 } else {
47 s.name
48 }
49 })
50 .collect();
51 Ok(names)
52 }
53 Mach::Fat(_) => Ok(vec![]),
54 },
55 Object::Archive(_) | Object::Unknown(_) => Ok(vec![]),
56 }
57}
58
59fn is_derive_registrar_symbol(symbol: &str) -> bool {
60 symbol.contains(NEW_REGISTRAR_SYMBOL)
61}
62
63fn find_registrar_symbol(file: &Path) -> Result<Option<String>, IoError> {
64 let symbols = get_symbols_from_lib(file)?;
65 Ok(symbols.into_iter().find(|s| is_derive_registrar_symbol(s)))
66}
67
68/// Loads dynamic library in platform dependent manner.
69///
70/// For unix, you have to use RTLD_DEEPBIND flag to escape problems described
71/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample)
72/// and [here](https://github.com/rust-lang/rust/issues/60593).
73///
74/// Usage of RTLD_DEEPBIND
75/// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1)
76///
77/// It seems that on Windows that behaviour is default, so we do nothing in that case.
78#[cfg(windows)]
79fn load_library(file: &Path) -> Result<Library, libloading::Error> {
80 Library::new(file)
81}
82
83#[cfg(unix)]
84fn load_library(file: &Path) -> Result<Library, libloading::Error> {
85 use libloading::os::unix::Library as UnixLibrary;
86 use std::os::raw::c_int;
87
88 const RTLD_NOW: c_int = 0x00002;
89 const RTLD_DEEPBIND: c_int = 0x00008;
90
91 UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into())
92}
93
94struct ProcMacroLibraryLibloading {
95 // Hold the dylib to prevent it for unloadeding
96 _lib: Library,
97 exported_macros: Vec<bridge::client::ProcMacro>,
98}
99
100impl ProcMacroLibraryLibloading {
101 fn open(file: &Path) -> Result<Self, IoError> {
102 let symbol_name = find_registrar_symbol(file)?
103 .ok_or(invalid_data_err(format!("Cannot find registrar symbol in file {:?}", file)))?;
104
105 let lib = load_library(file).map_err(invalid_data_err)?;
106 let exported_macros = {
107 let macros: libloading::Symbol<&&[bridge::client::ProcMacro]> =
108 unsafe { lib.get(symbol_name.as_bytes()) }.map_err(invalid_data_err)?;
109 macros.to_vec()
110 };
111
112 Ok(ProcMacroLibraryLibloading { _lib: lib, exported_macros })
113 }
114}
115
116type ProcMacroLibraryImpl = ProcMacroLibraryLibloading;
117
118pub struct Expander {
119 libs: Vec<ProcMacroLibraryImpl>,
120}
121
122impl Expander {
123 pub fn new<P: AsRef<Path>>(lib: &P) -> Result<Expander, String> {
124 let mut libs = vec![];
125 /* Some libraries for dynamic loading require canonicalized path (even when it is
126 already absolute
127 */
128 let lib =
129 lib.as_ref().canonicalize().expect(&format!("Cannot canonicalize {:?}", lib.as_ref()));
130
131 let library = ProcMacroLibraryImpl::open(&lib).map_err(|e| e.to_string())?;
132 libs.push(library);
133
134 Ok(Expander { libs })
135 }
136
137 pub fn expand(
138 &self,
139 macro_name: &str,
140 macro_body: &ra_tt::Subtree,
141 attributes: Option<&ra_tt::Subtree>,
142 ) -> Result<ra_tt::Subtree, bridge::PanicMessage> {
143 let parsed_body = TokenStream::with_subtree(macro_body.clone());
144
145 let parsed_attributes = attributes
146 .map_or(crate::rustc_server::TokenStream::new(), |attr| {
147 TokenStream::with_subtree(attr.clone())
148 });
149
150 for lib in &self.libs {
151 for proc_macro in &lib.exported_macros {
152 match proc_macro {
153 bridge::client::ProcMacro::CustomDerive { trait_name, client, .. }
154 if *trait_name == macro_name =>
155 {
156 let res = client.run(
157 &crate::proc_macro::bridge::server::SameThread,
158 crate::rustc_server::Rustc::default(),
159 parsed_body,
160 );
161 return res.map(|it| it.subtree);
162 }
163 bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => {
164 let res = client.run(
165 &crate::proc_macro::bridge::server::SameThread,
166 crate::rustc_server::Rustc::default(),
167 parsed_body,
168 );
169 return res.map(|it| it.subtree);
170 }
171 bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => {
172 let res = client.run(
173 &crate::proc_macro::bridge::server::SameThread,
174 crate::rustc_server::Rustc::default(),
175 parsed_attributes,
176 parsed_body,
177 );
178
179 return res.map(|it| it.subtree);
180 }
181 _ => continue,
182 }
183 }
184 }
185
186 Err(bridge::PanicMessage::String("Nothing to expand".to_string()))
187 }
188
189 pub fn list_macros(&self) -> Result<Vec<(String, ProcMacroKind)>, bridge::PanicMessage> {
190 let mut result = vec![];
191
192 for lib in &self.libs {
193 for proc_macro in &lib.exported_macros {
194 let res = match proc_macro {
195 bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
196 (trait_name.to_string(), ProcMacroKind::CustomDerive)
197 }
198 bridge::client::ProcMacro::Bang { name, .. } => {
199 (name.to_string(), ProcMacroKind::FuncLike)
200 }
201 bridge::client::ProcMacro::Attr { name, .. } => {
202 (name.to_string(), ProcMacroKind::Attr)
203 }
204 };
205 result.push(res);
206 }
207 }
208
209 Ok(result)
210 }
211}
diff --git a/crates/ra_proc_macro_srv/src/lib.rs b/crates/ra_proc_macro_srv/src/lib.rs
index f376df236..59716cbb3 100644
--- a/crates/ra_proc_macro_srv/src/lib.rs
+++ b/crates/ra_proc_macro_srv/src/lib.rs
@@ -17,13 +17,41 @@ mod proc_macro;
17#[doc(hidden)] 17#[doc(hidden)]
18mod rustc_server; 18mod rustc_server;
19 19
20mod dylib;
21
20use proc_macro::bridge::client::TokenStream; 22use proc_macro::bridge::client::TokenStream;
21use ra_proc_macro::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask}; 23use ra_proc_macro::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask};
22 24
23pub fn expand_task(_task: &ExpansionTask) -> Result<ExpansionResult, String> { 25pub fn expand_task(task: &ExpansionTask) -> Result<ExpansionResult, String> {
24 unimplemented!() 26 let expander = dylib::Expander::new(&task.lib)
27 .expect(&format!("Cannot expand with provided libraries: ${:?}", &task.lib));
28
29 match expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref()) {
30 Ok(expansion) => Ok(ExpansionResult { expansion }),
31 Err(msg) => {
32 let reason = format!(
33 "Cannot perform expansion for {}: error {:?}!",
34 &task.macro_name,
35 msg.as_str()
36 );
37 Err(reason)
38 }
39 }
25} 40}
26 41
27pub fn list_macros(_task: &ListMacrosTask) -> Result<ListMacrosResult, String> { 42pub fn list_macros(task: &ListMacrosTask) -> Result<ListMacrosResult, String> {
28 unimplemented!() 43 let expander = dylib::Expander::new(&task.lib)
44 .expect(&format!("Cannot expand with provided libraries: ${:?}", &task.lib));
45
46 match expander.list_macros() {
47 Ok(macros) => Ok(ListMacrosResult { macros }),
48 Err(msg) => {
49 let reason =
50 format!("Cannot perform expansion for {:?}: error {:?}!", &task.lib, msg.as_str());
51 Err(reason)
52 }
53 }
29} 54}
55
56#[cfg(test)]
57mod tests;
diff --git a/crates/ra_proc_macro_srv/src/rustc_server.rs b/crates/ra_proc_macro_srv/src/rustc_server.rs
index 92d1fd989..ec0d35692 100644
--- a/crates/ra_proc_macro_srv/src/rustc_server.rs
+++ b/crates/ra_proc_macro_srv/src/rustc_server.rs
@@ -34,6 +34,10 @@ impl TokenStream {
34 TokenStream { subtree: Default::default() } 34 TokenStream { subtree: Default::default() }
35 } 35 }
36 36
37 pub fn with_subtree(subtree: tt::Subtree) -> Self {
38 TokenStream { subtree }
39 }
<