aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yaml4
-rw-r--r--.github/workflows/release.yaml8
-rw-r--r--Cargo.lock91
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs27
-rw-r--r--crates/ra_assists/src/handlers/add_from_impl_for_enum.rs206
-rw-r--r--crates/ra_assists/src/handlers/add_function.rs788
-rw-r--r--crates/ra_assists/src/lib.rs9
-rw-r--r--crates/ra_hir/src/code_model.rs51
-rw-r--r--crates/ra_hir/src/diagnostics.rs2
-rw-r--r--crates/ra_hir/src/semantics.rs30
-rw-r--r--crates/ra_hir/src/semantics/source_to_def.rs18
-rw-r--r--crates/ra_hir/src/source_analyzer.rs90
-rw-r--r--crates/ra_hir_def/src/body/lower.rs3
-rw-r--r--crates/ra_hir_def/src/lib.rs5
-rw-r--r--crates/ra_hir_def/src/type_ref.rs6
-rw-r--r--crates/ra_hir_expand/src/builtin_derive.rs6
-rw-r--r--crates/ra_hir_ty/Cargo.toml7
-rw-r--r--crates/ra_hir_ty/src/_match.rs1411
-rw-r--r--crates/ra_hir_ty/src/autoderef.rs19
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs21
-rw-r--r--crates/ra_hir_ty/src/display.rs22
-rw-r--r--crates/ra_hir_ty/src/expr.rs205
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs17
-rw-r--r--crates/ra_hir_ty/src/infer/path.rs12
-rw-r--r--crates/ra_hir_ty/src/infer/unify.rs28
-rw-r--r--crates/ra_hir_ty/src/lib.rs108
-rw-r--r--crates/ra_hir_ty/src/lower.rs28
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs16
-rw-r--r--crates/ra_hir_ty/src/test_db.rs6
-rw-r--r--crates/ra_hir_ty/src/tests.rs3
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs14
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs31
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs85
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs5
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs30
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs37
-rw-r--r--crates/ra_hir_ty/src/traits.rs16
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs53
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs160
-rw-r--r--crates/ra_hir_ty/src/utils.rs6
-rw-r--r--crates/ra_ide/src/call_info.rs14
-rw-r--r--crates/ra_ide/src/completion.rs8
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_fn_param.rs4
-rw-r--r--crates/ra_ide/src/completion/complete_keyword.rs6
-rw-r--r--crates/ra_ide/src/completion/complete_pattern.rs58
-rw-r--r--crates/ra_ide/src/completion/complete_qualified_path.rs (renamed from crates/ra_ide/src/completion/complete_path.rs)26
-rw-r--r--crates/ra_ide/src/completion/complete_record.rs101
-rw-r--r--crates/ra_ide/src/completion/complete_unqualified_path.rs (renamed from crates/ra_ide/src/completion/complete_scope.rs)12
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs35
-rw-r--r--crates/ra_ide/src/completion/presentation.rs278
-rw-r--r--crates/ra_ide/src/diagnostics.rs10
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs42
-rw-r--r--crates/ra_ide/src/display/structure.rs16
-rw-r--r--crates/ra_ide/src/goto_type_definition.rs6
-rw-r--r--crates/ra_ide/src/lib.rs5
-rw-r--r--crates/ra_ide/src/marks.rs1
-rw-r--r--crates/ra_ide/src/runnables.rs4
-rw-r--r--crates/ra_ide/src/ssr.rs122
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs2
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tags.rs6
-rw-r--r--crates/ra_ide_db/src/search.rs2
-rw-r--r--crates/ra_ide_db/src/symbol_index.rs16
-rw-r--r--crates/ra_mbe/src/tests.rs17
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs4
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs25
-rw-r--r--crates/ra_parser/src/grammar/types.rs2
-rw-r--r--crates/ra_parser/src/syntax_kind/generated.rs1
-rw-r--r--crates/ra_proc_macro/src/lib.rs3
-rw-r--r--crates/ra_proc_macro_srv/Cargo.toml20
-rw-r--r--crates/ra_proc_macro_srv/src/lib.rs26
-rw-r--r--crates/ra_proc_macro_srv/src/main.rs55
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/bridge/buffer.rs149
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/bridge/client.rs472
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/bridge/closure.rs27
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/bridge/handle.rs73
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/bridge/mod.rs404
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/bridge/rpc.rs311
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/bridge/scoped_cell.rs84
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/bridge/server.rs323
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/diagnostic.rs172
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/mod.rs926
-rw-r--r--crates/ra_project_model/src/lib.rs129
-rw-r--r--crates/ra_syntax/Cargo.toml2
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs3
-rw-r--r--crates/ra_syntax/src/ast/generated.rs42
-rw-r--r--crates/ra_syntax/src/ast/make.rs28
-rw-r--r--crates/ra_syntax/src/tests.rs14
-rw-r--r--crates/ra_syntax/src/validation.rs12
-rw-r--r--crates/ra_syntax/test_data/parser/err/0000_struct_field_missing_comma.rast (renamed from crates/ra_syntax/test_data/parser/err/0000_struct_field_missing_comma.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0001_item_recovery_in_file.rast (renamed from crates/ra_syntax/test_data/parser/err/0001_item_recovery_in_file.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.rast (renamed from crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0003_C++_semicolon.rast (renamed from crates/ra_syntax/test_data/parser/err/0003_C++_semicolon.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.rast (renamed from crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0005_attribute_recover.rast (renamed from crates/ra_syntax/test_data/parser/err/0005_attribute_recover.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0006_named_field_recovery.rast (renamed from crates/ra_syntax/test_data/parser/err/0006_named_field_recovery.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0007_stray_curly_in_file.rast (renamed from crates/ra_syntax/test_data/parser/err/0007_stray_curly_in_file.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0008_item_block_recovery.rast (renamed from crates/ra_syntax/test_data/parser/err/0008_item_block_recovery.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0009_broken_struct_type_parameter.rast (renamed from crates/ra_syntax/test_data/parser/err/0009_broken_struct_type_parameter.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.rast (renamed from crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0011_extern_struct.rast (renamed from crates/ra_syntax/test_data/parser/err/0011_extern_struct.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0012_broken_lambda.rast (renamed from crates/ra_syntax/test_data/parser/err/0012_broken_lambda.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0013_invalid_type.rast (renamed from crates/ra_syntax/test_data/parser/err/0013_invalid_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0014_where_no_bounds.rast (renamed from crates/ra_syntax/test_data/parser/err/0014_where_no_bounds.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0015_curly_in_params.rast (renamed from crates/ra_syntax/test_data/parser/err/0015_curly_in_params.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0016_missing_semi.rast (renamed from crates/ra_syntax/test_data/parser/err/0016_missing_semi.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0017_incomplete_binexpr.rast (renamed from crates/ra_syntax/test_data/parser/err/0017_incomplete_binexpr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0018_incomplete_fn.rast (renamed from crates/ra_syntax/test_data/parser/err/0018_incomplete_fn.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0019_let_recover.rast (renamed from crates/ra_syntax/test_data/parser/err/0019_let_recover.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0020_fn_recover.rast (renamed from crates/ra_syntax/test_data/parser/err/0020_fn_recover.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0021_incomplete_param.rast (renamed from crates/ra_syntax/test_data/parser/err/0021_incomplete_param.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0022_bad_exprs.rast (renamed from crates/ra_syntax/test_data/parser/err/0022_bad_exprs.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0023_mismatched_paren.rast (renamed from crates/ra_syntax/test_data/parser/err/0023_mismatched_paren.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0024_many_type_parens.rast (renamed from crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0025_nope.rast (renamed from crates/ra_syntax/test_data/parser/err/0025_nope.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0026_imp_recovery.rast (renamed from crates/ra_syntax/test_data/parser/err/0026_imp_recovery.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.rast (renamed from crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0029_field_completion.rast (renamed from crates/ra_syntax/test_data/parser/err/0029_field_completion.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0031_block_inner_attrs.rast (renamed from crates/ra_syntax/test_data/parser/err/0031_block_inner_attrs.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.rast (renamed from crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0033_match_arms_outer_attrs.rast (renamed from crates/ra_syntax/test_data/parser/err/0033_match_arms_outer_attrs.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.rast (renamed from crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0035_use_recover.rast (renamed from crates/ra_syntax/test_data/parser/err/0035_use_recover.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0036_partial_use.rast (renamed from crates/ra_syntax/test_data/parser/err/0036_partial_use.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.rast (renamed from crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.rast (renamed from crates/ra_syntax/test_data/parser/err/0038_endless_inclusive_range.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rast (renamed from crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0001_array_type_missing_semi.rast (renamed from crates/ra_syntax/test_data/parser/inline/err/0001_array_type_missing_semi.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0002_misplaced_label_err.rast (renamed from crates/ra_syntax/test_data/parser/inline/err/0002_misplaced_label_err.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0003_pointer_type_no_mutability.rast (renamed from crates/ra_syntax/test_data/parser/inline/err/0003_pointer_type_no_mutability.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0004_impl_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/err/0004_impl_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rast (renamed from crates/ra_syntax/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0006_unsafe_block_in_mod.rast (renamed from crates/ra_syntax/test_data/parser/inline/err/0006_unsafe_block_in_mod.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0007_async_without_semicolon.rast (renamed from crates/ra_syntax/test_data/parser/inline/err/0007_async_without_semicolon.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0008_pub_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/err/0008_pub_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.rast (renamed from crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast (renamed from crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0013_static_underscore.rast (renamed from crates/ra_syntax/test_data/parser/inline/err/0013_static_underscore.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0001_trait_item_list.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0001_trait_item_list.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0002_use_tree_list.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0003_where_pred_for.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0005_function_type_params.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0005_function_type_params.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0006_self_param.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0006_self_param.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0007_type_param_bounds.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0007_type_param_bounds.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0008_path_part.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0008_path_part.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0009_loop_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0009_loop_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0010_extern_block.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0010_extern_block.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0012_type_item_where_clause.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0012_type_item_where_clause.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0013_pointer_type_mut.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0013_pointer_type_mut.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0014_never_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0014_never_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0015_continue_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0015_continue_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0017_array_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0017_array_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0018_arb_self_types.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0018_arb_self_types.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0019_unary_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0019_unary_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0020_use_star.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0020_use_star.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0021_impl_item_list.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0021_impl_item_list.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0022_crate_visibility.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0022_crate_visibility.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0023_placeholder_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0023_placeholder_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0024_slice_pat.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0024_slice_pat.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0025_slice_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0025_slice_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0026_tuple_pat_fields.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0026_tuple_pat_fields.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0027_ref_pat.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0027_ref_pat.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0028_impl_trait_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0028_impl_trait_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0029_cast_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0029_cast_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0030_cond.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0030_cond.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0032_fn_pointer_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0032_fn_pointer_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0033_reference_type;.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0033_reference_type;.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0034_break_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0034_break_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0037_qual_paths.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0037_qual_paths.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0038_full_range_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0038_full_range_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0039_type_arg.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0040_crate_keyword_vis.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0040_crate_keyword_vis.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0041_trait_item.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0041_trait_item.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0042_call_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0042_call_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0043_use_alias.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0043_use_alias.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0044_block_items.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0044_block_items.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0045_param_list_opt_patterns.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0046_singleton_tuple_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0046_singleton_tuple_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0048_path_type_with_bounds.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0050_fn_decl.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0050_fn_decl.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0051_unit_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0051_unit_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0052_path_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0052_path_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0053_path_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0053_path_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0054_record_field_attrs.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0054_record_field_attrs.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0055_literal_pattern.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0055_literal_pattern.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0056_where_clause.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0056_where_clause.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0058_range_pat.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0058_range_pat.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0059_match_arms_commas.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0059_match_arms_commas.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0060_extern_crate.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0060_extern_crate.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0061_record_lit.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0062_mod_contents.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0062_mod_contents.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0063_impl_def_neg.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0063_impl_def_neg.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0065_dyn_trait_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0065_dyn_trait_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0067_crate_path.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0067_crate_path.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0068_union_items.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0068_union_items.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0069_use_tree_list_after_path.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0072_return_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0072_return_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0073_type_item_type_params.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0073_type_item_type_params.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0075_block.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0075_block.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0076_function_where_clause.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0076_function_where_clause.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0077_try_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0077_try_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0078_type_item.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0078_type_item.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0079_impl_def.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0079_impl_def.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0081_for_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0082_ref_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0083_struct_items.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0083_struct_items.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0084_paren_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0084_paren_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0085_expr_literals.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0085_expr_literals.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0086_function_ret_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0086_function_ret_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0088_break_ambiguity.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0088_break_ambiguity.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0090_type_param_default.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0090_type_param_default.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0093_index_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0093_index_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0095_placeholder_pat.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0095_placeholder_pat.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0096_no_semi_after_block.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0096_no_semi_after_block.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0099_param_list.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0099_param_list.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0100_for_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0100_for_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0102_record_field_pat_list.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0103_array_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0103_array_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0105_block_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0105_block_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0106_lambda_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0106_lambda_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0107_method_call_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0107_method_call_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0108_tuple_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0108_tuple_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0109_label.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0109_label.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0110_use_path.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0110_use_path.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0112_bind_pat.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0113_nocontentexpr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0113_nocontentexpr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0114_tuple_struct_where.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0114_tuple_struct_where.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0117_macro_call_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0117_macro_call_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0118_match_guard.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0118_match_guard.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0123_param_list_vararg.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0123_param_list_vararg.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0125_crate_keyword_path.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0125_crate_keyword_path.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt)21
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0130_let_stmt.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0130_let_stmt.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0130_try_block_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0130_try_block_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0131_existential_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0131_existential_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0132_box_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0132_box_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0134_nocontentexpr_after_item.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0138_expression_after_block.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0138_expression_after_block.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0142_for_range_from.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0142_for_range_from.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0143_box_pat.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0144_dot_dot_pat.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0144_dot_dot_pat.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0145_record_field_pat.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0150_array_attrs.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0150_array_attrs.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0150_impl_type_params.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0150_impl_type_params.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0151_trait_alias.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0151_trait_alias.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0152_arg_with_attr.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0152_arg_with_attr.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0156_fn_def_param.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0156_fn_def_param.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0157_variant_discriminant.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0157_variant_discriminant.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0158_binop_resets_statementness.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0158_binop_resets_statementness.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0158_lambda_ret_block.rast (renamed from crates/ra_syntax/test_data/parser/inline/ok/0158_lambda_ret_block.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0000_empty.rast (renamed from crates/ra_syntax/test_data/parser/ok/0000_empty.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0001_struct_item.rast (renamed from crates/ra_syntax/test_data/parser/ok/0001_struct_item.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0002_struct_item_field.rast (renamed from crates/ra_syntax/test_data/parser/ok/0002_struct_item_field.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0004_file_shebang.rast (renamed from crates/ra_syntax/test_data/parser/ok/0004_file_shebang.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0005_fn_item.rast (renamed from crates/ra_syntax/test_data/parser/ok/0005_fn_item.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0006_inner_attributes.rast (renamed from crates/ra_syntax/test_data/parser/ok/0006_inner_attributes.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0007_extern_crate.rast (renamed from crates/ra_syntax/test_data/parser/ok/0007_extern_crate.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0008_mod_item.rast (renamed from crates/ra_syntax/test_data/parser/ok/0008_mod_item.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0009_use_item.rast (renamed from crates/ra_syntax/test_data/parser/ok/0009_use_item.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0010_use_path_segments.rast (renamed from crates/ra_syntax/test_data/parser/ok/0010_use_path_segments.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0011_outer_attribute.rast (renamed from crates/ra_syntax/test_data/parser/ok/0011_outer_attribute.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0012_visibility.rast (renamed from crates/ra_syntax/test_data/parser/ok/0012_visibility.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.rast (renamed from crates/ra_syntax/test_data/parser/ok/0013_use_path_self_super.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0014_use_tree.rast (renamed from crates/ra_syntax/test_data/parser/ok/0014_use_tree.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0015_use_tree.rast (renamed from crates/ra_syntax/test_data/parser/ok/0015_use_tree.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0016_struct_flavors.rast (renamed from crates/ra_syntax/test_data/parser/ok/0016_struct_flavors.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0017_attr_trailing_comma.rast (renamed from crates/ra_syntax/test_data/parser/ok/0017_attr_trailing_comma.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0018_struct_type_params.rast (renamed from crates/ra_syntax/test_data/parser/ok/0018_struct_type_params.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0019_enums.rast (renamed from crates/ra_syntax/test_data/parser/ok/0019_enums.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0020_type_param_bounds.rast (renamed from crates/ra_syntax/test_data/parser/ok/0020_type_param_bounds.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rast (renamed from crates/ra_syntax/test_data/parser/ok/0021_extern_fn.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0022_empty_extern_block.rast (renamed from crates/ra_syntax/test_data/parser/ok/0022_empty_extern_block.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0023_static_items.rast (renamed from crates/ra_syntax/test_data/parser/ok/0023_static_items.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0024_const_item.rast (renamed from crates/ra_syntax/test_data/parser/ok/0024_const_item.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0025_extern_fn_in_block.rast (renamed from crates/ra_syntax/test_data/parser/ok/0025_extern_fn_in_block.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0026_const_fn_in_block.rast (renamed from crates/ra_syntax/test_data/parser/ok/0026_const_fn_in_block.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0027_unsafe_fn_in_block.rast (renamed from crates/ra_syntax/test_data/parser/ok/0027_unsafe_fn_in_block.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0028_operator_binding_power.rast (renamed from crates/ra_syntax/test_data/parser/ok/0028_operator_binding_power.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0029_range_forms.rast (renamed from crates/ra_syntax/test_data/parser/ok/0029_range_forms.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0030_string_suffixes.rast (renamed from crates/ra_syntax/test_data/parser/ok/0030_string_suffixes.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0030_traits.rast (renamed from crates/ra_syntax/test_data/parser/ok/0030_traits.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0031_extern.rast (renamed from crates/ra_syntax/test_data/parser/ok/0031_extern.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0032_where_for.rast (renamed from crates/ra_syntax/test_data/parser/ok/0032_where_for.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0033_label_break.rast (renamed from crates/ra_syntax/test_data/parser/ok/0033_label_break.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0034_crate_path_in_call.rast (renamed from crates/ra_syntax/test_data/parser/ok/0034_crate_path_in_call.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.rast (renamed from crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0036_fully_qualified.rast (renamed from crates/ra_syntax/test_data/parser/ok/0036_fully_qualified.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0037_mod.rast (renamed from crates/ra_syntax/test_data/parser/ok/0037_mod.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0038_where_pred_type.rast (renamed from crates/ra_syntax/test_data/parser/ok/0038_where_pred_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0039_raw_fn_item.rast (renamed from crates/ra_syntax/test_data/parser/ok/0039_raw_fn_item.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0040_raw_struct_item_field.rast (renamed from crates/ra_syntax/test_data/parser/ok/0040_raw_struct_item_field.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0041_raw_keywords.rast (renamed from crates/ra_syntax/test_data/parser/ok/0041_raw_keywords.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0042_ufcs_call_list.rast (renamed from crates/ra_syntax/test_data/parser/ok/0042_ufcs_call_list.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0043_complex_assignment.rast (renamed from crates/ra_syntax/test_data/parser/ok/0043_complex_assignment.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0044_let_attrs.rast (renamed from crates/ra_syntax/test_data/parser/ok/0044_let_attrs.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0045_block_inner_attrs.rast (renamed from crates/ra_syntax/test_data/parser/ok/0045_block_inner_attrs.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0046_extern_inner_attributes.rast (renamed from crates/ra_syntax/test_data/parser/ok/0046_extern_inner_attributes.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0047_minus_in_inner_pattern.rast (renamed from crates/ra_syntax/test_data/parser/ok/0047_minus_in_inner_pattern.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0048_compound_assignment.rast (renamed from crates/ra_syntax/test_data/parser/ok/0048_compound_assignment.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0049_async_block.rast (renamed from crates/ra_syntax/test_data/parser/ok/0049_async_block.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0050_async_block_as_argument.rast (renamed from crates/ra_syntax/test_data/parser/ok/0050_async_block_as_argument.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.rast (renamed from crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0052_for_range_block.rast (renamed from crates/ra_syntax/test_data/parser/ok/0052_for_range_block.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast (renamed from crates/ra_syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.rast (renamed from crates/ra_syntax/test_data/parser/ok/0054_qual_path_in_type_arg.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.rast (renamed from crates/ra_syntax/test_data/parser/ok/0055_dot_dot_dot.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0056_neq_in_type.rast (renamed from crates/ra_syntax/test_data/parser/ok/0056_neq_in_type.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.rast (renamed from crates/ra_syntax/test_data/parser/ok/0057_loop_in_call.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rast (renamed from crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.rast (renamed from crates/ra_syntax/test_data/parser/ok/0059_loops_in_parens.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0060_as_range.rast (renamed from crates/ra_syntax/test_data/parser/ok/0060_as_range.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0061_match_full_range.rast (renamed from crates/ra_syntax/test_data/parser/ok/0061_match_full_range.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.rast (renamed from crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.rast (renamed from crates/ra_syntax/test_data/parser/ok/0063_trait_fn_patterns.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0063_variadic_fun.rast (renamed from crates/ra_syntax/test_data/parser/ok/0063_variadic_fun.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.rast (renamed from crates/ra_syntax/test_data/parser/ok/0064_impl_fn_params.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0065_comment_newline.rast (renamed from crates/ra_syntax/test_data/parser/ok/0065_comment_newline.txt)0
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs11
-rw-r--r--crates/rust-analyzer/src/config.rs62
-rw-r--r--crates/rust-analyzer/src/conv.rs4
-rw-r--r--crates/rust-analyzer/src/lib.rs13
-rw-r--r--crates/rust-analyzer/src/main_loop.rs5
-rw-r--r--crates/rust-analyzer/src/main_loop/subscriptions.rs2
-rw-r--r--crates/rust-analyzer/src/semantic_tokens.rs4
-rw-r--r--crates/rust-analyzer/src/vfs_glob.rs10
-rw-r--r--crates/rust-analyzer/src/world.rs57
-rw-r--r--crates/stdx/src/lib.rs15
-rw-r--r--crates/test_utils/src/lib.rs34
-rw-r--r--docs/user/assists.md26
-rw-r--r--editors/code/.vscodeignore1
-rw-r--r--editors/code/package-lock.json82
-rw-r--r--editors/code/package.json128
-rw-r--r--editors/code/src/main.ts2
-rw-r--r--xtask/src/ast_src.rs3
-rw-r--r--xtask/src/dist.rs20
-rw-r--r--xtask/src/lib.rs8
-rw-r--r--xtask/src/main.rs14
-rw-r--r--xtask/src/not_bash.rs4
386 files changed, 7376 insertions, 934 deletions
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index fb7afe9fd..02a3b6228 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -10,7 +10,7 @@ on:
10env: 10env:
11 CARGO_INCREMENTAL: 0 11 CARGO_INCREMENTAL: 0
12 CARGO_NET_RETRY: 10 12 CARGO_NET_RETRY: 10
13 RUN_SLOW_TESTS: 1 13 CI: 1
14 RUST_BACKTRACE: short 14 RUST_BACKTRACE: short
15 RUSTFLAGS: -D warnings 15 RUSTFLAGS: -D warnings
16 RUSTUP_MAX_RETRIES: 10 16 RUSTUP_MAX_RETRIES: 10
@@ -45,7 +45,7 @@ jobs:
45 name: Rust 45 name: Rust
46 runs-on: ${{ matrix.os }} 46 runs-on: ${{ matrix.os }}
47 env: 47 env:
48 CC: deny_c 48 CC: deny_c
49 49
50 strategy: 50 strategy:
51 fail-fast: false 51 fail-fast: false
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index fd184e8f1..2c1192f07 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -50,16 +50,20 @@ jobs:
50 50
51 - name: Dist 51 - name: Dist
52 if: matrix.os == 'ubuntu-latest' && github.ref == 'refs/heads/release' 52 if: matrix.os == 'ubuntu-latest' && github.ref == 'refs/heads/release'
53 run: cargo xtask dist --client --version 0.2.$GITHUB_RUN_NUMBER --tag $(date --iso --utc) 53 run: cargo xtask dist --client 0.2.$GITHUB_RUN_NUMBER
54 54
55 - name: Dist 55 - name: Dist
56 if: matrix.os == 'ubuntu-latest' && github.ref != 'refs/heads/release' 56 if: matrix.os == 'ubuntu-latest' && github.ref != 'refs/heads/release'
57 run: cargo xtask dist --client --version 0.3.$GITHUB_RUN_NUMBER-nightly --tag nightly 57 run: cargo xtask dist --nightly --client 0.3.$GITHUB_RUN_NUMBER-nightly
58 58
59 - name: Dist 59 - name: Dist
60 if: matrix.os != 'ubuntu-latest' 60 if: matrix.os != 'ubuntu-latest'
61 run: cargo xtask dist 61 run: cargo xtask dist
62 62
63 - name: Nightly analysis-stats check
64 if: matrix.os == 'ubuntu-latest' && github.ref != 'refs/heads/release'
65 run: ./dist/rust-analyzer-linux analysis-stats .
66
63 - name: Upload artifacts 67 - name: Upload artifacts
64 uses: actions/upload-artifact@v1 68 uses: actions/upload-artifact@v1
65 with: 69 with:
diff --git a/Cargo.lock b/Cargo.lock
index c07a9614a..eb9824218 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -114,7 +114,7 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
114[[package]] 114[[package]]
115name = "chalk-derive" 115name = "chalk-derive"
116version = "0.1.0" 116version = "0.1.0"
117source = "git+https://github.com/rust-lang/chalk.git?rev=177d71340acc7a7204a33115fc63075d86452179#177d71340acc7a7204a33115fc63075d86452179" 117source = "git+https://github.com/rust-lang/chalk.git?rev=039fc904a05f8cb3d0c682c9a57a63dda7a35356#039fc904a05f8cb3d0c682c9a57a63dda7a35356"
118dependencies = [ 118dependencies = [
119 "proc-macro2", 119 "proc-macro2",
120 "quote", 120 "quote",
@@ -124,7 +124,7 @@ dependencies = [
124[[package]] 124[[package]]
125name = "chalk-engine" 125name = "chalk-engine"
126version = "0.9.0" 126version = "0.9.0"
127source = "git+https://github.com/rust-lang/chalk.git?rev=177d71340acc7a7204a33115fc63075d86452179#177d71340acc7a7204a33115fc63075d86452179" 127source = "git+https://github.com/rust-lang/chalk.git?rev=039fc904a05f8cb3d0c682c9a57a63dda7a35356#039fc904a05f8cb3d0c682c9a57a63dda7a35356"
128dependencies = [ 128dependencies = [
129 "chalk-macros", 129 "chalk-macros",
130 "rustc-hash", 130 "rustc-hash",
@@ -133,7 +133,7 @@ dependencies = [
133[[package]] 133[[package]]
134name = "chalk-ir" 134name = "chalk-ir"
135version = "0.1.0" 135version = "0.1.0"
136source = "git+https://github.com/rust-lang/chalk.git?rev=177d71340acc7a7204a33115fc63075d86452179#177d71340acc7a7204a33115fc63075d86452179" 136source = "git+https://github.com/rust-lang/chalk.git?rev=039fc904a05f8cb3d0c682c9a57a63dda7a35356#039fc904a05f8cb3d0c682c9a57a63dda7a35356"
137dependencies = [ 137dependencies = [
138 "chalk-derive", 138 "chalk-derive",
139 "chalk-engine", 139 "chalk-engine",
@@ -143,7 +143,7 @@ dependencies = [
143[[package]] 143[[package]]
144name = "chalk-macros" 144name = "chalk-macros"
145version = "0.1.1" 145version = "0.1.1"
146source = "git+https://github.com/rust-lang/chalk.git?rev=177d71340acc7a7204a33115fc63075d86452179#177d71340acc7a7204a33115fc63075d86452179" 146source = "git+https://github.com/rust-lang/chalk.git?rev=039fc904a05f8cb3d0c682c9a57a63dda7a35356#039fc904a05f8cb3d0c682c9a57a63dda7a35356"
147dependencies = [ 147dependencies = [
148 "lazy_static", 148 "lazy_static",
149] 149]
@@ -151,7 +151,7 @@ dependencies = [
151[[package]] 151[[package]]
152name = "chalk-rust-ir" 152name = "chalk-rust-ir"
153version = "0.1.0" 153version = "0.1.0"
154source = "git+https://github.com/rust-lang/chalk.git?rev=177d71340acc7a7204a33115fc63075d86452179#177d71340acc7a7204a33115fc63075d86452179" 154source = "git+https://github.com/rust-lang/chalk.git?rev=039fc904a05f8cb3d0c682c9a57a63dda7a35356#039fc904a05f8cb3d0c682c9a57a63dda7a35356"
155dependencies = [ 155dependencies = [
156 "chalk-derive", 156 "chalk-derive",
157 "chalk-engine", 157 "chalk-engine",
@@ -162,7 +162,7 @@ dependencies = [
162[[package]] 162[[package]]
163name = "chalk-solve" 163name = "chalk-solve"
164version = "0.1.0" 164version = "0.1.0"
165source = "git+https://github.com/rust-lang/chalk.git?rev=177d71340acc7a7204a33115fc63075d86452179#177d71340acc7a7204a33115fc63075d86452179" 165source = "git+https://github.com/rust-lang/chalk.git?rev=039fc904a05f8cb3d0c682c9a57a63dda7a35356#039fc904a05f8cb3d0c682c9a57a63dda7a35356"
166dependencies = [ 166dependencies = [
167 "chalk-derive", 167 "chalk-derive",
168 "chalk-engine", 168 "chalk-engine",
@@ -170,7 +170,7 @@ dependencies = [
170 "chalk-macros", 170 "chalk-macros",
171 "chalk-rust-ir", 171 "chalk-rust-ir",
172 "ena", 172 "ena",
173 "itertools 0.8.2", 173 "itertools",
174 "petgraph", 174 "petgraph",
175 "rustc-hash", 175 "rustc-hash",
176] 176]
@@ -380,9 +380,9 @@ dependencies = [
380 380
381[[package]] 381[[package]]
382name = "fst" 382name = "fst"
383version = "0.4.0" 383version = "0.4.1"
384source = "registry+https://github.com/rust-lang/crates.io-index" 384source = "registry+https://github.com/rust-lang/crates.io-index"
385checksum = "3f7c13470d799474d44e2b9c6a0925807def7af4d120cd4de761433be76f7579" 385checksum = "4eaf9ea41cc964d742f7fc7861db75d2d6e83a3ce0d897d5c6f8b621f015ddc8"
386 386
387[[package]] 387[[package]]
388name = "fuchsia-zircon" 388name = "fuchsia-zircon"
@@ -507,15 +507,6 @@ dependencies = [
507 507
508[[package]] 508[[package]]
509name = "itertools" 509name = "itertools"
510version = "0.8.2"
511source = "registry+https://github.com/rust-lang/crates.io-index"
512checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
513dependencies = [
514 "either",
515]
516
517[[package]]
518name = "itertools"
519version = "0.9.0" 510version = "0.9.0"
520source = "registry+https://github.com/rust-lang/crates.io-index" 511source = "registry+https://github.com/rust-lang/crates.io-index"
521checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" 512checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
@@ -792,9 +783,9 @@ dependencies = [
792 783
793[[package]] 784[[package]]
794name = "paste" 785name = "paste"
795version = "0.1.9" 786version = "0.1.10"
796source = "registry+https://github.com/rust-lang/crates.io-index" 787source = "registry+https://github.com/rust-lang/crates.io-index"
797checksum = "092d791bf7847f70bbd49085489fba25fc2c193571752bff9e36e74e72403932" 788checksum = "ab4fb1930692d1b6a9cfabdde3d06ea0a7d186518e2f4d67660d8970e2fa647a"
798dependencies = [ 789dependencies = [
799 "paste-impl", 790 "paste-impl",
800 "proc-macro-hack", 791 "proc-macro-hack",
@@ -802,9 +793,9 @@ dependencies = [
802 793
803[[package]] 794[[package]]
804name = "paste-impl" 795name = "paste-impl"
805version = "0.1.9" 796version = "0.1.10"
806source = "registry+https://github.com/rust-lang/crates.io-index" 797source = "registry+https://github.com/rust-lang/crates.io-index"
807checksum = "406c23fb4c45cc6f68a9bbabb8ec7bd6f8cfcbd17e9e8f72c2460282f8325729" 798checksum = "a62486e111e571b1e93b710b61e8f493c0013be39629b714cb166bdb06aa5a8a"
808dependencies = [ 799dependencies = [
809 "proc-macro-hack", 800 "proc-macro-hack",
810 "proc-macro2", 801 "proc-macro2",
@@ -873,7 +864,7 @@ name = "ra_assists"
873version = "0.1.0" 864version = "0.1.0"
874dependencies = [ 865dependencies = [
875 "either", 866 "either",
876 "itertools 0.9.0", 867 "itertools",
877 "ra_db", 868 "ra_db",
878 "ra_fmt", 869 "ra_fmt",
879 "ra_hir", 870 "ra_hir",
@@ -927,7 +918,7 @@ dependencies = [
927name = "ra_fmt" 918name = "ra_fmt"
928version = "0.1.0" 919version = "0.1.0"
929dependencies = [ 920dependencies = [
930 "itertools 0.9.0", 921 "itertools",
931 "ra_syntax", 922 "ra_syntax",
932] 923]
933 924
@@ -937,7 +928,7 @@ version = "0.1.0"
937dependencies = [ 928dependencies = [
938 "arrayvec", 929 "arrayvec",
939 "either", 930 "either",
940 "itertools 0.9.0", 931 "itertools",
941 "log", 932 "log",
942 "ra_db", 933 "ra_db",
943 "ra_hir_def", 934 "ra_hir_def",
@@ -1004,6 +995,7 @@ dependencies = [
1004 "ra_prof", 995 "ra_prof",
1005 "ra_syntax", 996 "ra_syntax",
1006 "rustc-hash", 997 "rustc-hash",
998 "smallvec",
1007 "stdx", 999 "stdx",
1008 "test_utils", 1000 "test_utils",
1009] 1001]
@@ -1015,7 +1007,7 @@ dependencies = [
1015 "either", 1007 "either",
1016 "indexmap", 1008 "indexmap",
1017 "insta", 1009 "insta",
1018 "itertools 0.9.0", 1010 "itertools",
1019 "log", 1011 "log",
1020 "ra_assists", 1012 "ra_assists",
1021 "ra_cfg", 1013 "ra_cfg",
@@ -1084,6 +1076,17 @@ dependencies = [
1084] 1076]
1085 1077
1086[[package]] 1078[[package]]
1079name = "ra_proc_macro_srv"
1080version = "0.1.0"
1081dependencies = [
1082 "cargo_metadata",
1083 "difference",
1084 "ra_proc_macro",
1085 "ra_tt",
1086 "serde_derive",
1087]
1088
1089[[package]]
1087name = "ra_prof" 1090name = "ra_prof"
1088version = "0.1.0" 1091version = "0.1.0"
1089dependencies = [ 1092dependencies = [
@@ -1114,13 +1117,13 @@ name = "ra_syntax"
1114version = "0.1.0" 1117version = "0.1.0"
1115dependencies = [ 1118dependencies = [
1116 "arrayvec", 1119 "arrayvec",
1117 "itertools 0.9.0", 1120 "itertools",
1118 "once_cell", 1121 "once_cell",
1119 "ra_parser", 1122 "ra_parser",
1120 "ra_text_edit", 1123 "ra_text_edit",
1121 "rowan", 1124 "rowan",
1125 "rustc-ap-rustc_lexer",
1122 "rustc-hash", 1126 "rustc-hash",
1123 "rustc_lexer",
1124 "serde", 1127 "serde",
1125 "smol_str", 1128 "smol_str",
1126 "stdx", 1129 "stdx",
@@ -1292,7 +1295,7 @@ dependencies = [
1292 "crossbeam-channel", 1295 "crossbeam-channel",
1293 "env_logger", 1296 "env_logger",
1294 "globset", 1297 "globset",
1295 "itertools 0.9.0", 1298 "itertools",
1296 "jod-thread", 1299 "jod-thread",
1297 "log", 1300 "log",
1298 "lsp-server", 1301 "lsp-server",
@@ -1323,6 +1326,15 @@ dependencies = [
1323] 1326]
1324 1327
1325[[package]] 1328[[package]]
1329name = "rustc-ap-rustc_lexer"
1330version = "652.0.0"
1331source = "registry+https://github.com/rust-lang/crates.io-index"
1332checksum = "3a6a43c4d0889218c5e2ae68ffea239f303fc05ab1078c73f74e63feb87f7889"
1333dependencies = [
1334 "unicode-xid",
1335]
1336
1337[[package]]
1326name = "rustc-demangle" 1338name = "rustc-demangle"
1327version = "0.1.16" 1339version = "0.1.16"
1328source = "registry+https://github.com/rust-lang/crates.io-index" 1340source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1335,15 +1347,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1335checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1347checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
1336 1348
1337[[package]] 1349[[package]]
1338name = "rustc_lexer"
1339version = "0.1.0"
1340source = "registry+https://github.com/rust-lang/crates.io-index"
1341checksum = "c86aae0c77166108c01305ee1a36a1e77289d7dc6ca0a3cd91ff4992de2d16a5"
1342dependencies = [
1343 "unicode-xid",
1344]
1345
1346[[package]]
1347name = "ryu" 1350name = "ryu"
1348version = "1.0.3" 1351version = "1.0.3"
1349source = "registry+https://github.com/rust-lang/crates.io-index" 1352source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1410,18 +1413,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
1410 1413
1411[[package]] 1414[[package]]
1412name = "serde" 1415name = "serde"
1413version = "1.0.105" 1416version = "1.0.104"
1414source = "registry+https://github.com/rust-lang/crates.io-index" 1417source = "registry+https://github.com/rust-lang/crates.io-index"
1415checksum = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" 1418checksum = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
1416dependencies = [ 1419dependencies = [
1417 "serde_derive", 1420 "serde_derive",
1418] 1421]
1419 1422
1420[[package]] 1423[[package]]
1421name = "serde_derive" 1424name = "serde_derive"
1422version = "1.0.105" 1425version = "1.0.104"
1423source = "registry+https://github.com/rust-lang/crates.io-index" 1426source = "registry+https://github.com/rust-lang/crates.io-index"
1424checksum = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" 1427checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
1425dependencies = [ 1428dependencies = [
1426 "proc-macro2", 1429 "proc-macro2",
1427 "quote", 1430 "quote",
@@ -1430,9 +1433,9 @@ dependencies = [
1430 1433
1431[[package]] 1434[[package]]
1432name = "serde_json" 1435name = "serde_json"
1433version = "1.0.50" 1436version = "1.0.51"
1434source = "registry+https://github.com/rust-lang/crates.io-index" 1437source = "registry+https://github.com/rust-lang/crates.io-index"
1435checksum = "78a7a12c167809363ec3bd7329fc0a3369056996de43c4b37ef3cd54a6ce4867" 1438checksum = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9"
1436dependencies = [ 1439dependencies = [
1437 "itoa", 1440 "itoa",
1438 "ryu", 1441 "ryu",
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index 0848ab6bc..64444ee3a 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -59,6 +59,33 @@ fn main() {
59} 59}
60 60
61#[test] 61#[test]
62fn doctest_add_function() {
63 check(
64 "add_function",
65 r#####"
66struct Baz;
67fn baz() -> Baz { Baz }
68fn foo() {
69 bar<|>("", baz());
70}
71
72"#####,
73 r#####"
74struct Baz;
75fn baz() -> Baz { Baz }
76fn foo() {
77 bar("", baz());
78}
79
80fn bar(arg: &str, baz: Baz) {
81 unimplemented!()
82}
83
84"#####,
85 )
86}
87
88#[test]
62fn doctest_add_hash() { 89fn doctest_add_hash() {
63 check( 90 check(
64 "add_hash", 91 "add_hash",
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
new file mode 100644
index 000000000..864373aa5
--- /dev/null
+++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
@@ -0,0 +1,206 @@
1use ra_syntax::{
2 ast::{self, AstNode, NameOwner},
3 TextUnit,
4};
5use stdx::format_to;
6
7use crate::{Assist, AssistCtx, AssistId};
8use ra_ide_db::RootDatabase;
9
10// Assist add_from_impl_for_enum
11//
12// Adds a From impl for an enum variant with one tuple field
13//
14// ```
15// enum A { <|>One(u32) }
16// ```
17// ->
18// ```
19// enum A { One(u32) }
20//
21// impl From<u32> for A {
22// fn from(v: u32) -> Self {
23// A::One(v)
24// }
25// }
26// ```
27pub(crate) fn add_from_impl_for_enum(ctx: AssistCtx) -> Option<Assist> {
28 let variant = ctx.find_node_at_offset::<ast::EnumVariant>()?;
29 let variant_name = variant.name()?;
30 let enum_name = variant.parent_enum().name()?;
31 let field_list = match variant.kind() {
32 ast::StructKind::Tuple(field_list) => field_list,
33 _ => return None,
34 };
35 if field_list.fields().count() != 1 {
36 return None;
37 }
38 let field_type = field_list.fields().next()?.type_ref()?;
39 let path = match field_type {
40 ast::TypeRef::PathType(p) => p,
41 _ => return None,
42 };
43
44 if already_has_from_impl(ctx.sema, &variant) {
45 return None;
46 }
47
48 ctx.add_assist(
49 AssistId("add_from_impl_for_enum"),
50 "Add From impl for this enum variant",
51 |edit| {
52 let start_offset = variant.parent_enum().syntax().text_range().end();
53 let mut buf = String::new();
54 format_to!(
55 buf,
56 r#"
57
58impl From<{0}> for {1} {{
59 fn from(v: {0}) -> Self {{
60 {1}::{2}(v)
61 }}
62}}"#,
63 path.syntax(),
64 enum_name,
65 variant_name
66 );
67 edit.insert(start_offset, buf);
68 edit.set_cursor(start_offset + TextUnit::of_str("\n\n"));
69 },
70 )
71}
72
73fn already_has_from_impl(
74 sema: &'_ hir::Semantics<'_, RootDatabase>,
75 variant: &ast::EnumVariant,
76) -> bool {
77 let scope = sema.scope(&variant.syntax());
78
79 let from_path = ast::make::path_from_text("From");
80 let from_hir_path = match hir::Path::from_ast(from_path) {
81 Some(p) => p,
82 None => return false,
83 };
84 let from_trait = match scope.resolve_hir_path(&from_hir_path) {
85 Some(hir::PathResolution::Def(hir::ModuleDef::Trait(t))) => t,
86 _ => return false,
87 };
88
89 let e: hir::Enum = match sema.to_def(&variant.parent_enum()) {
90 Some(e) => e,
91 None => return false,
92 };
93 let e_ty = e.ty(sema.db);
94
95 let hir_enum_var: hir::EnumVariant = match sema.to_def(variant) {
96 Some(ev) => ev,
97 None => return false,
98 };
99 let var_ty = hir_enum_var.fields(sema.db)[0].signature_ty(sema.db);
100
101 e_ty.impls_trait(sema.db, from_trait, &[var_ty.clone()])
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use crate::helpers::{check_assist, check_assist_not_applicable};
108
109 #[test]
110 fn test_add_from_impl_for_enum() {
111 check_assist(
112 add_from_impl_for_enum,
113 "enum A { <|>One(u32) }",
114 r#"enum A { One(u32) }
115
116<|>impl From<u32> for A {
117 fn from(v: u32) -> Self {
118 A::One(v)
119 }
120}"#,
121 );
122 }
123
124 #[test]
125 fn test_add_from_impl_for_enum_complicated_path() {
126 check_assist(
127 add_from_impl_for_enum,
128 "enum A { <|>One(foo::bar::baz::Boo) }",
129 r#"enum A { One(foo::bar::baz::Boo) }
130
131<|>impl From<foo::bar::baz::Boo> for A {
132 fn from(v: foo::bar::baz::Boo) -> Self {
133 A::One(v)
134 }
135}"#,
136 );
137 }
138
139 #[test]
140 fn test_add_from_impl_no_element() {
141 check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One }");
142 }
143
144 #[test]
145 fn test_add_from_impl_more_than_one_element_in_tuple() {
146 check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One(u32, String) }");
147 }
148
149 #[test]
150 fn test_add_from_impl_struct_variant() {
151 check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One { x: u32 } }");
152 }
153
154 #[test]
155 fn test_add_from_impl_already_exists() {
156 check_assist_not_applicable(
157 add_from_impl_for_enum,
158 r#"enum A { <|>One(u32), }
159
160impl From<u32> for A {
161 fn from(v: u32) -> Self {
162 A::One(v)
163 }
164}
165
166pub trait From<T> {
167 fn from(T) -> Self;
168}"#,
169 );
170 }
171
172 #[test]
173 fn test_add_from_impl_different_variant_impl_exists() {
174 check_assist(
175 add_from_impl_for_enum,
176 r#"enum A { <|>One(u32), Two(String), }
177
178impl From<String> for A {
179 fn from(v: String) -> Self {
180 A::Two(v)
181 }
182}
183
184pub trait From<T> {
185 fn from(T) -> Self;
186}"#,
187 r#"enum A { One(u32), Two(String), }
188
189<|>impl From<u32> for A {
190 fn from(v: u32) -> Self {
191 A::One(v)
192 }
193}
194
195impl From<String> for A {
196 fn from(v: String) -> Self {
197 A::Two(v)
198 }
199}
200
201pub trait From<T> {
202 fn from(T) -> Self;
203}"#,
204 );
205 }
206}
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs
new file mode 100644
index 000000000..488bae08f
--- /dev/null
+++ b/crates/ra_assists/src/handlers/add_function.rs
@@ -0,0 +1,788 @@
1use ra_syntax::{
2 ast::{self, AstNode},
3 SyntaxKind, SyntaxNode, TextUnit,
4};
5
6use crate::{Assist, AssistCtx, AssistId};
7use ast::{edit::IndentLevel, ArgListOwner, CallExpr, Expr};
8use hir::HirDisplay;
9use rustc_hash::{FxHashMap, FxHashSet};
10
11// Assist: add_function
12//
13// Adds a stub function with a signature matching the function under the cursor.
14//
15// ```
16// struct Baz;
17// fn baz() -> Baz { Baz }
18// fn foo() {
19// bar<|>("", baz());
20// }
21//
22// ```
23// ->
24// ```
25// struct Baz;
26// fn baz() -> Baz { Baz }
27// fn foo() {
28// bar("", baz());
29// }
30//
31// fn bar(arg: &str, baz: Baz) {
32// unimplemented!()
33// }
34//
35// ```
36pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> {
37 let path_expr: ast::PathExpr = ctx.find_node_at_offset()?;
38 let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
39 let path = path_expr.path()?;
40
41 if path.qualifier().is_some() {
42 return None;
43 }
44
45 if ctx.sema.resolve_path(&path).is_some() {
46 // The function call already resolves, no need to add a function
47 return None;
48 }
49
50 let function_builder = FunctionBuilder::from_call(&ctx, &call)?;
51
52 ctx.add_assist(AssistId("add_function"), "Add function", |edit| {
53 edit.target(call.syntax().text_range());
54
55 if let Some(function_template) = function_builder.render() {
56 edit.set_cursor(function_template.cursor_offset);
57 edit.insert(function_template.insert_offset, function_template.fn_def.to_string());
58 }
59 })
60}
61
62struct FunctionTemplate {
63 insert_offset: TextUnit,
64 cursor_offset: TextUnit,
65 fn_def: ast::SourceFile,
66}
67
68struct FunctionBuilder {
69 append_fn_at: SyntaxNode,
70 fn_name: ast::Name,
71 type_params: Option<ast::TypeParamList>,
72 params: ast::ParamList,
73}
74
75impl FunctionBuilder {
76 fn from_call(ctx: &AssistCtx, call: &ast::CallExpr) -> Option<Self> {
77 let append_fn_at = next_space_for_fn(&call)?;
78 let fn_name = fn_name(&call)?;
79 let (type_params, params) = fn_args(ctx, &call)?;
80 Some(Self { append_fn_at, fn_name, type_params, params })
81 }
82 fn render(self) -> Option<FunctionTemplate> {
83 let placeholder_expr = ast::make::expr_unimplemented();
84 let fn_body = ast::make::block_expr(vec![], Some(placeholder_expr));
85 let fn_def = ast::make::fn_def(self.fn_name, self.type_params, self.params, fn_body);
86 let fn_def = ast::make::add_newlines(2, fn_def);
87 let fn_def = IndentLevel::from_node(&self.append_fn_at).increase_indent(fn_def);
88 let insert_offset = self.append_fn_at.text_range().end();
89 let cursor_offset_from_fn_start = fn_def
90 .syntax()
91 .descendants()
92 .find_map(ast::MacroCall::cast)?
93 .syntax()
94 .text_range()
95 .start();
96 let cursor_offset = insert_offset + cursor_offset_from_fn_start;
97 Some(FunctionTemplate { insert_offset, cursor_offset, fn_def })
98 }
99}
100
101fn fn_name(call: &CallExpr) -> Option<ast::Name> {
102 let name = call.expr()?.syntax().to_string();
103 Some(ast::make::name(&name))
104}
105
106/// Computes the type variables and arguments required for the generated function
107fn fn_args(
108 ctx: &AssistCtx,
109 call: &CallExpr,
110) -> Option<(Option<ast::TypeParamList>, ast::ParamList)> {
111 let mut arg_names = Vec::new();
112 let mut arg_types = Vec::new();
113 for arg in call.arg_list()?.args() {
114 let arg_name = match fn_arg_name(&arg) {
115 Some(name) => name,
116 None => String::from("arg"),
117 };
118 arg_names.push(arg_name);
119 arg_types.push(match fn_arg_type(ctx, &arg) {
120 Some(ty) => ty,
121 None => String::from("()"),
122 });
123 }
124 deduplicate_arg_names(&mut arg_names);
125 let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| ast::make::param(name, ty));
126 Some((None, ast::make::param_list(params)))
127}
128
129/// Makes duplicate argument names unique by appending incrementing numbers.
130///
131/// ```
132/// let mut names: Vec<String> =
133/// vec!["foo".into(), "foo".into(), "bar".into(), "baz".into(), "bar".into()];
134/// deduplicate_arg_names(&mut names);
135/// let expected: Vec<String> =
136/// vec!["foo_1".into(), "foo_2".into(), "bar_1".into(), "baz".into(), "bar_2".into()];
137/// assert_eq!(names, expected);
138/// ```
139fn deduplicate_arg_names(arg_names: &mut Vec<String>) {
140 let arg_name_counts = arg_names.iter().fold(FxHashMap::default(), |mut m, name| {
141 *m.entry(name).or_insert(0) += 1;
142 m
143 });
144 let duplicate_arg_names: FxHashSet<String> = arg_name_counts
145 .into_iter()
146 .filter(|(_, count)| *count >= 2)
147 .map(|(name, _)| name.clone())
148 .collect();
149
150 let mut counter_per_name = FxHashMap::default();
151 for arg_name in arg_names.iter_mut() {
152 if duplicate_arg_names.contains(arg_name) {
153 let counter = counter_per_name.entry(arg_name.clone()).or_insert(1);
154 arg_name.push('_');
155 arg_name.push_str(&counter.to_string());
156 *counter += 1;
157 }
158 }
159}
160
161fn fn_arg_name(fn_arg: &Expr) -> Option<String> {
162 match fn_arg {
163 Expr::CastExpr(cast_expr) => fn_arg_name(&cast_expr.expr()?),
164 _ => Some(
165 fn_arg
166 .syntax()
167 .descendants()
168 .filter(|d| ast::NameRef::can_cast(d.kind()))
169 .last()?
170 .to_string(),
171 ),
172 }
173}
174
175fn fn_arg_type(ctx: &AssistCtx, fn_arg: &Expr) -> Option<String> {
176 let ty = ctx.sema.type_of_expr(fn_arg)?;
177 if ty.is_unknown() {
178 return None;
179 }
180 Some(ty.display(ctx.sema.db).to_string())
181}
182
183/// Returns the position inside the current mod or file
184/// directly after the current block
185/// We want to write the generated function directly after
186/// fns, impls or macro calls, but inside mods
187fn next_space_for_fn(expr: &CallExpr) -> Option<SyntaxNode> {
188 let mut ancestors = expr.syntax().ancestors().peekable();
189 let mut last_ancestor: Option<SyntaxNode> = None;
190 while let Some(next_ancestor) = ancestors.next() {
191 match next_ancestor.kind() {
192 SyntaxKind::SOURCE_FILE => {
193 break;
194 }
195 SyntaxKind::ITEM_LIST => {
196 if ancestors.peek().map(|a| a.kind()) == Some(SyntaxKind::MODULE) {
197 break;
198 }
199 }
200 _ => {}
201 }
202 last_ancestor = Some(next_ancestor);
203 }
204 last_ancestor
205}
206
207#[cfg(test)]
208mod tests {
209 use crate::helpers::{check_assist, check_assist_not_applicable};
210
211 use super::*;
212
213 #[test]
214 fn add_function_with_no_args() {
215 check_assist(
216 add_function,
217 r"
218fn foo() {
219 bar<|>();
220}
221",
222 r"
223fn foo() {
224 bar();
225}
226
227fn bar() {
228 <|>unimplemented!()
229}
230",
231 )
232 }
233
234 #[test]
235 fn add_function_from_method() {
236 // This ensures that the function is correctly generated
237 // in the next outer mod or file
238 check_assist(
239 add_function,
240 r"
241impl Foo {
242 fn foo() {
243 bar<|>();
244 }
245}
246",
247 r"
248impl Foo {
249 fn foo() {
250 bar();
251 }
252}
253
254fn bar() {
255 <|>unimplemented!()
256}
257",
258 )
259 }
260
261 #[test]
262 fn add_function_directly_after_current_block() {
263 // The new fn should not be created at the end of the file or module
264 check_assist(
265 add_function,
266 r"
267fn foo1() {
268 bar<|>();
269}
270
271fn foo2() {}
272",
273 r"
274fn foo1() {
275 bar();
276}
277
278fn bar() {
279 <|>unimplemented!()
280}
281
282fn foo2() {}
283",
284 )
285 }
286
287 #[test]
288 fn add_function_with_no_args_in_same_module() {
289 check_assist(
290 add_function,
291 r"
292mod baz {
293 fn foo() {
294 bar<|>();
295 }
296}
297",
298 r"
299mod baz {
300 fn foo() {
301 bar();
302 }
303
304 fn bar() {
305 <|>unimplemented!()
306 }
307}
308",
309 )
310 }
311
312 #[test]
313 fn add_function_with_function_call_arg() {
314 check_assist(
315 add_function,
316 r"
317struct Baz;
318fn baz() -> Baz { unimplemented!() }
319fn foo() {
320 bar<|>(baz());
321}
322",
323 r"
324struct Baz;
325fn baz() -> Baz { unimplemented!() }
326fn foo() {
327 bar(baz());
328}
329
330fn bar(baz: Baz) {
331 <|>unimplemented!()
332}
333",
334 );
335 }
336
337 #[test]
338 fn add_function_with_method_call_arg() {
339 check_assist(
340 add_function,
341 r"
342struct Baz;
343impl Baz {
344 fn foo(&self) -> Baz {
345 ba<|>r(self.baz())
346 }
347 fn baz(&self) -> Baz {
348 Baz
349 }
350}
351",
352 r"
353struct Baz;
354impl Baz {
355 fn foo(&self) -> Baz {
356 bar(self.baz())
357 }
358 fn baz(&self) -> Baz {
359 Baz
360 }
361}
362
363fn bar(baz: Baz) {
364 <|>unimplemented!()
365}
366",
367 )
368 }
369
370 #[test]
371 fn add_function_with_string_literal_arg() {
372 check_assist(
373 add_function,
374 r#"
375fn foo() {
376 <|>bar("bar")
377}
378"#,
379 r#"
380fn foo() {
381 bar("bar")
382}
383
384fn bar(arg: &str) {
385 <|>unimplemented!()
386}
387"#,
388 )
389 }
390
391 #[test]
392 fn add_function_with_char_literal_arg() {
393 check_assist(
394 add_function,
395 r#"
396fn foo() {
397 <|>bar('x')
398}
399"#,
400 r#"
401fn foo() {
402 bar('x')
403}
404
405fn bar(arg: char) {
406 <|>unimplemented!()
407}
408"#,
409 )
410 }
411
412 #[test]
413 fn add_function_with_int_literal_arg() {
414 check_assist(
415 add_function,
416 r"
417fn foo() {
418 <|>bar(42)
419}
420",
421 r"
422fn foo() {
423 bar(42)
424}
425
426fn bar(arg: i32) {
427 <|>unimplemented!()
428}
429",
430 )
431 }
432
433 #[test]
434 fn add_function_with_cast_int_literal_arg() {
435 check_assist(
436 add_function,
437 r"
438fn foo() {
439 <|>bar(42 as u8)
440}
441",
442 r"
443fn foo() {
444 bar(42 as u8)
445}
446
447fn bar(arg: u8) {
448 <|>unimplemented!()
449}
450",
451 )
452 }
453
454 #[test]
455 fn name_of_cast_variable_is_used() {
456 // Ensures that the name of the cast type isn't used
457 // in the generated function signature.
458 check_assist(
459 add_function,
460 r"
461fn foo() {
462 let x = 42;
463 bar<|>(x as u8)
464}
465",
466 r"
467fn foo() {
468 let x = 42;
469 bar(x as u8)
470}
471
472fn bar(x: u8) {
473 <|>unimplemented!()
474}
475",
476 )
477 }
478
479 #[test]
480 fn add_function_with_variable_arg() {
481 check_assist(
482 add_function,
483 r"
484fn foo() {
485 let worble = ();
486 <|>bar(worble)
487}
488",
489 r"
490fn foo() {
491 let worble = ();
492 bar(worble)
493}
494
495fn bar(worble: ()) {
496 <|>unimplemented!()
497}
498",
499 )
500 }
501
502 #[test]
503 fn add_function_with_impl_trait_arg() {
504 check_assist(
505 add_function,
506 r"
507trait Foo {}
508fn foo() -> impl Foo {
509 unimplemented!()
510}
511fn baz() {
512 <|>bar(foo())
513}
514",
515 r"
516trait Foo {}
517fn foo() -> impl Foo {
518 unimplemented!()
519}
520fn baz() {
521 bar(foo())
522}
523
524fn bar(foo: impl Foo) {
525 <|>unimplemented!()
526}
527",
528 )
529 }
530
531 #[test]
532 #[ignore]
533 // FIXME print paths properly to make this test pass
534 fn add_function_with_qualified_path_arg() {
535 check_assist(
536 add_function,
537 r"
538mod Baz {
539 pub struct Bof;
540 pub fn baz() -> Bof { Bof }
541}
542mod Foo {
543 fn foo() {
544 <|>bar(super::Baz::baz())
545 }
546}
547",
548 r"
549mod Baz {
550 pub struct Bof;
551 pub fn baz() -> Bof { Bof }
552}
553mod Foo {
554 fn foo() {
555 bar(super::Baz::baz())
556 }
557
558 fn bar(baz: super::Baz::Bof) {
559 <|>unimplemented!()
560 }
561}
562",
563 )
564 }
565
566 #[test]
567 #[ignore]
568 // FIXME fix printing the generics of a `Ty` to make this test pass
569 fn add_function_with_generic_arg() {
570 check_assist(
571 add_function,
572 r"
573fn foo<T>(t: T) {
574 <|>bar(t)
575}
576",
577 r"
578fn foo<T>(t: T) {
579 bar(t)
580}
581
582fn bar<T>(t: T) {
583 <|>unimplemented!()
584}
585",
586 )
587 }
588
589 #[test]
590 #[ignore]
591 // FIXME Fix function type printing to make this test pass
592 fn add_function_with_fn_arg() {
593 check_assist(
594 add_function,
595 r"
596struct Baz;
597impl Baz {
598 fn new() -> Self { Baz }
599}
600fn foo() {
601 <|>bar(Baz::new);
602}
603",
604 r"
605struct Baz;
606impl Baz {
607 fn new() -> Self { Baz }
608}
609fn foo() {
610 bar(Baz::new);
611}
612
613fn bar(arg: fn() -> Baz) {
614 <|>unimplemented!()
615}
616",
617 )
618 }
619
620 #[test]
621 #[ignore]
622 // FIXME Fix closure type printing to make this test pass
623 fn add_function_with_closure_arg() {
624 check_assist(
625 add_function,
626 r"
627fn foo() {
628 let closure = |x: i64| x - 1;
629 <|>bar(closure)
630}
631",
632 r"
633fn foo() {
634 let closure = |x: i64| x - 1;
635 bar(closure)
636}
637
638fn bar(closure: impl Fn(i64) -> i64) {
639 <|>unimplemented!()
640}
641",
642 )
643 }
644
645 #[test]
646 fn unresolveable_types_default_to_unit() {
647 check_assist(
648 add_function,
649 r"
650fn foo() {
651 <|>bar(baz)
652}
653",
654 r"
655fn foo() {
656 bar(baz)
657}
658
659fn bar(baz: ()) {
660 <|>unimplemented!()
661}
662",
663 )
664 }
665
666 #[test]
667 fn arg_names_dont_overlap() {
668 check_assist(
669 add_function,
670 r"
671struct Baz;
672fn baz() -> Baz { Baz }
673fn foo() {
674 <|>bar(baz(), baz())
675}
676",
677 r"
678struct Baz;
679fn baz() -> Baz { Baz }
680fn foo() {
681 bar(baz(), baz())
682}
683
684fn bar(baz_1: Baz, baz_2: Baz) {
685 <|>unimplemented!()
686}
687",
688 )
689 }
690
691 #[test]
692 fn arg_name_counters_start_at_1_per_name() {
693 check_assist(
694 add_function,
695 r#"
696struct Baz;
697fn baz() -> Baz { Baz }
698fn foo() {
699 <|>bar(baz(), baz(), "foo", "bar")
700}
701"#,
702 r#"
703struct Baz;
704fn baz() -> Baz { Baz }
705fn foo() {
706 bar(baz(), baz(), "foo", "bar")
707}
708
709fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) {
710 <|>unimplemented!()
711}
712"#,
713 )
714 }
715
716 #[test]
717 fn add_function_not_applicable_if_function_already_exists() {
718 check_assist_not_applicable(
719 add_function,
720 r"
721fn foo() {
722 bar<|>();
723}
724
725fn bar() {}
726",
727 )
728 }
729
730 #[test]
731 fn add_function_not_applicable_if_unresolved_variable_in_call_is_selected() {
732 check_assist_not_applicable(
733 // bar is resolved, but baz isn't.
734 // The assist is only active if the cursor is on an unresolved path,
735 // but the assist should only be offered if the path is a function call.
736 add_function,
737 r"
738fn foo() {
739 bar(b<|>az);
740}
741
742fn bar(baz: ()) {}
743",
744 )
745 }
746
747 #[test]
748 fn add_function_not_applicable_if_function_path_not_singleton() {
749 // In the future this assist could be extended to generate functions
750 // if the path is in the same crate (or even the same workspace).
751 // For the beginning, I think this is fine.
752 check_assist_not_applicable(
753 add_function,
754 r"
755fn foo() {
756 other_crate::bar<|>();
757}
758 ",
759 )
760 }
761
762 #[test]
763 #[ignore]
764 fn create_method_with_no_args() {
765 check_assist(
766 add_function,
767 r"
768struct Foo;
769impl Foo {
770 fn foo(&self) {
771 self.bar()<|>;
772 }
773}
774 ",
775 r"
776struct Foo;
777impl Foo {
778 fn foo(&self) {
779 self.bar();
780 }
781 fn bar(&self) {
782 unimplemented!();
783 }
784}
785 ",
786 )
787 }
788}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index fa1f3dd26..c698d6e8c 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -5,6 +5,11 @@
5//! certain context. For example, if the cursor is over `,`, a "swap `,`" assist 5//! certain context. For example, if the cursor is over `,`, a "swap `,`" assist
6//! becomes available. 6//! becomes available.
7 7
8#[allow(unused)]
9macro_rules! eprintln {
10 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
11}
12
8mod assist_ctx; 13mod assist_ctx;
9mod marks; 14mod marks;
10#[cfg(test)] 15#[cfg(test)]
@@ -96,6 +101,7 @@ mod handlers {
96 mod add_custom_impl; 101 mod add_custom_impl;
97 mod add_derive; 102 mod add_derive;
98 mod add_explicit_type; 103 mod add_explicit_type;
104 mod add_function;
99 mod add_impl; 105 mod add_impl;
100 mod add_missing_impl_members; 106 mod add_missing_impl_members;
101 mod add_new; 107 mod add_new;
@@ -122,12 +128,14 @@ mod handlers {
122 mod replace_qualified_name_with_use; 128 mod replace_qualified_name_with_use;
123 mod replace_unwrap_with_match; 129 mod replace_unwrap_with_match;
124 mod split_import; 130 mod split_import;
131 mod add_from_impl_for_enum;
125 132
126 pub(crate) fn all() -> &'static [AssistHandler] { 133 pub(crate) fn all() -> &'static [AssistHandler] {
127 &[ 134 &[
128 add_custom_impl::add_custom_impl, 135 add_custom_impl::add_custom_impl,
129 add_derive::add_derive, 136 add_derive::add_derive,
130 add_explicit_type::add_explicit_type, 137 add_explicit_type::add_explicit_type,
138 add_function::add_function,
131 add_impl::add_impl, 139 add_impl::add_impl,
132 add_missing_impl_members::add_missing_default_members, 140 add_missing_impl_members::add_missing_default_members,
133 add_missing_impl_members::add_missing_impl_members, 141 add_missing_impl_members::add_missing_impl_members,
@@ -159,6 +167,7 @@ mod handlers {
159 replace_qualified_name_with_use::replace_qualified_name_with_use, 167 replace_qualified_name_with_use::replace_qualified_name_with_use,
160 replace_unwrap_with_match::replace_unwrap_with_match, 168 replace_unwrap_with_match::replace_unwrap_with_match,
161 split_import::split_import, 169 split_import::split_import,
170 add_from_impl_for_enum::add_from_impl_for_enum,
162 ] 171 ]
163 } 172 }
164} 173}
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index cd2a8fc62..9baebf643 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1027,8 +1027,16 @@ impl Type {
1027 ty: Ty, 1027 ty: Ty,
1028 ) -> Option<Type> { 1028 ) -> Option<Type> {
1029 let krate = resolver.krate()?; 1029 let krate = resolver.krate()?;
1030 Some(Type::new_with_resolver_inner(db, krate, resolver, ty))
1031 }
1032 pub(crate) fn new_with_resolver_inner(
1033 db: &dyn HirDatabase,
1034 krate: CrateId,
1035 resolver: &Resolver,
1036 ty: Ty,
1037 ) -> Type {
1030 let environment = TraitEnvironment::lower(db, &resolver); 1038 let environment = TraitEnvironment::lower(db, &resolver);
1031 Some(Type { krate, ty: InEnvironment { value: ty, environment } }) 1039 Type { krate, ty: InEnvironment { value: ty, environment } }
1032 } 1040 }
1033 1041
1034 fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type { 1042 fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type {
@@ -1084,6 +1092,26 @@ impl Type {
1084 ) 1092 )
1085 } 1093 }
1086 1094
1095 pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
1096 let trait_ref = hir_ty::TraitRef {
1097 trait_: trait_.id,
1098 substs: Substs::build_for_def(db, trait_.id)
1099 .push(self.ty.value.clone())
1100 .fill(args.iter().map(|t| t.ty.value.clone()))
1101 .build(),
1102 };
1103
1104 let goal = Canonical {
1105 value: hir_ty::InEnvironment::new(
1106 self.ty.environment.clone(),
1107 hir_ty::Obligation::Trait(trait_ref),
1108 ),
1109 num_vars: 0,
1110 };
1111
1112 db.trait_solve(self.krate, goal).is_some()
1113 }
1114
1087 // FIXME: this method is broken, as it doesn't take closures into account. 1115 // FIXME: this method is broken, as it doesn't take closures into account.
1088 pub fn as_callable(&self) -> Option<CallableDef> { 1116 pub fn as_callable(&self) -> Option<CallableDef> {
1089 Some(self.ty.value.as_callable()?.0) 1117 Some(self.ty.value.as_callable()?.0)
@@ -1132,27 +1160,6 @@ impl Type {
1132 res 1160 res
1133 } 1161 }
1134 1162
1135 pub fn variant_fields(
1136 &self,
1137 db: &dyn HirDatabase,
1138 def: VariantDef,
1139 ) -> Vec<(StructField, Type)> {
1140 // FIXME: check that ty and def match
1141 match &self.ty.value {
1142 Ty::Apply(a_ty) => {
1143 let field_types = db.field_types(def.into());
1144 def.fields(db)
1145 .into_iter()
1146 .map(|it| {
1147 let ty = field_types[it.id].clone().subst(&a_ty.parameters);
1148 (it, self.derived(ty))
1149 })
1150 .collect()
1151 }
1152 _ => Vec::new(),
1153 }
1154 }
1155
1156 pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a { 1163 pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
1157 // There should be no inference vars in types passed here 1164 // There should be no inference vars in types passed here
1158 // FIXME check that? 1165 // FIXME check that?
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs
index a9040ea3d..c82883d0c 100644
--- a/crates/ra_hir/src/diagnostics.rs
+++ b/crates/ra_hir/src/diagnostics.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2pub use hir_def::diagnostics::UnresolvedModule; 2pub use hir_def::diagnostics::UnresolvedModule;
3pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; 3pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
4pub use hir_ty::diagnostics::{MissingFields, MissingOkInTailExpr, NoSuchField}; 4pub use hir_ty::diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField};
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index 16a5fe968..2707e422d 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -9,6 +9,7 @@ use hir_def::{
9 AsMacroCall, TraitId, 9 AsMacroCall, TraitId,
10}; 10};
11use hir_expand::ExpansionInfo; 11use hir_expand::ExpansionInfo;
12use itertools::Itertools;
12use ra_db::{FileId, FileRange}; 13use ra_db::{FileId, FileRange};
13use ra_prof::profile; 14use ra_prof::profile;
14use ra_syntax::{ 15use ra_syntax::{
@@ -22,7 +23,7 @@ use crate::{
22 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, 23 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
23 source_analyzer::{resolve_hir_path, SourceAnalyzer}, 24 source_analyzer::{resolve_hir_path, SourceAnalyzer},
24 AssocItem, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, Name, 25 AssocItem, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, Name,
25 Origin, Path, ScopeDef, StructField, Trait, Type, TypeParam, VariantDef, 26 Origin, Path, ScopeDef, StructField, Trait, Type, TypeParam,
26}; 27};
27 28
28#[derive(Debug, Clone, PartialEq, Eq)] 29#[derive(Debug, Clone, PartialEq, Eq)]
@@ -135,7 +136,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
135 node: &SyntaxNode, 136 node: &SyntaxNode,
136 offset: TextUnit, 137 offset: TextUnit,
137 ) -> impl Iterator<Item = SyntaxNode> + '_ { 138 ) -> impl Iterator<Item = SyntaxNode> + '_ {
138 use itertools::Itertools;
139 node.token_at_offset(offset) 139 node.token_at_offset(offset)
140 .map(|token| self.ancestors_with_macros(token.parent())) 140 .map(|token| self.ancestors_with_macros(token.parent()))
141 .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) 141 .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
@@ -187,14 +187,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
187 self.analyze(field.syntax()).resolve_record_field(self.db, field) 187 self.analyze(field.syntax()).resolve_record_field(self.db, field)
188 } 188 }
189 189
190 pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<VariantDef> {
191 self.analyze(record_lit.syntax()).resolve_record_literal(self.db, record_lit)
192 }
193
194 pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<VariantDef> {
195 self.analyze(record_pat.syntax()).resolve_record_pattern(record_pat)
196 }
197
198 pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> { 190 pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> {
199 let sa = self.analyze(macro_call.syntax()); 191 let sa = self.analyze(macro_call.syntax());
200 let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); 192 let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call);
@@ -212,6 +204,24 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
212 // FIXME: use this instead? 204 // FIXME: use this instead?
213 // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>; 205 // pub fn resolve_name_ref(&self, name_ref: &ast::NameRef) -> Option<???>;
214 206
207 pub fn record_literal_missing_fields(
208 &self,
209 literal: &ast::RecordLit,
210 ) -> Vec<(StructField, Type)> {
211 self.analyze(literal.syntax())
212 .record_literal_missing_fields(self.db, literal)
213 .unwrap_or_default()
214 }
215
216 pub fn record_pattern_missing_fields(
217 &self,
218 pattern: &ast::RecordPat,
219 ) -> Vec<(StructField, Type)> {
220 self.analyze(pattern.syntax())
221 .record_pattern_missing_fields(self.db, pattern)
222 .unwrap_or_default()
223 }
224
215 pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> { 225 pub fn to_def<T: ToDef>(&self, src: &T) -> Option<T::Def> {
216 let src = self.find_file(src.syntax().clone()).with_value(src).cloned(); 226 let src = self.find_file(src.syntax().clone()).with_value(src).cloned();
217 T::to_def(self, src) 227 T::to_def(self, src)
diff --git a/crates/ra_hir/src/semantics/source_to_def.rs b/crates/ra_hir/src/semantics/source_to_def.rs
index 8843f2835..66724919b 100644
--- a/crates/ra_hir/src/semantics/source_to_def.rs
+++ b/crates/ra_hir/src/semantics/source_to_def.rs
@@ -208,12 +208,12 @@ impl SourceToDefCtx<'_, '_> {
208 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { 208 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) {
209 let res: GenericDefId = match_ast! { 209 let res: GenericDefId = match_ast! {
210 match (container.value) { 210 match (container.value) {
211 ast::FnDef(it) => { self.fn_to_def(container.with_value(it))?.into() }, 211 ast::FnDef(it) => self.fn_to_def(container.with_value(it))?.into(),
212 ast::StructDef(it) => { self.struct_to_def(container.with_value(it))?.into() }, 212 ast::StructDef(it) => self.struct_to_def(container.with_value(it))?.into(),
213 ast::EnumDef(it) => { self.enum_to_def(container.with_value(it))?.into() }, 213 ast::EnumDef(it) => self.enum_to_def(container.with_value(it))?.into(),
214 ast::TraitDef(it) => { self.trait_to_def(container.with_value(it))?.into() }, 214 ast::TraitDef(it) => self.trait_to_def(container.with_value(it))?.into(),
215 ast::TypeAliasDef(it) => { self.type_alias_to_def(container.with_value(it))?.into() }, 215 ast::TypeAliasDef(it) => self.type_alias_to_def(container.with_value(it))?.into(),
216 ast::ImplDef(it) => { self.impl_to_def(container.with_value(it))?.into() }, 216 ast::ImplDef(it) => self.impl_to_def(container.with_value(it))?.into(),
217 _ => continue, 217 _ => continue,
218 } 218 }
219 }; 219 };
@@ -226,9 +226,9 @@ impl SourceToDefCtx<'_, '_> {
226 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { 226 for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) {
227 let res: DefWithBodyId = match_ast! { 227 let res: DefWithBodyId = match_ast! {
228 match (container.value) { 228 match (container.value) {
229 ast::ConstDef(it) => { self.const_to_def(container.with_value(it))?.into() }, 229 ast::ConstDef(it) => self.const_to_def(container.with_value(it))?.into(),
230 ast::StaticDef(it) => { self.static_to_def(container.with_value(it))?.into() }, 230 ast::StaticDef(it) => self.static_to_def(container.with_value(it))?.into(),
231 ast::FnDef(it) => { self.fn_to_def(container.with_value(it))?.into() }, 231 ast::FnDef(it) => self.fn_to_def(container.with_value(it))?.into(),
232 _ => continue, 232 _ => continue,
233 } 233 }
234 }; 234 };
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index 815ca158c..45631f8fd 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -14,10 +14,13 @@ use hir_def::{
14 }, 14 },
15 expr::{ExprId, Pat, PatId}, 15 expr::{ExprId, Pat, PatId},
16 resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, 16 resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
17 AsMacroCall, DefWithBodyId, 17 AsMacroCall, DefWithBodyId, LocalStructFieldId, StructFieldId, VariantId,
18}; 18};
19use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; 19use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
20use hir_ty::InferenceResult; 20use hir_ty::{
21 expr::{record_literal_missing_fields, record_pattern_missing_fields},
22 InferenceResult, Substs, Ty,
23};
21use ra_syntax::{ 24use ra_syntax::{
22 ast::{self, AstNode}, 25 ast::{self, AstNode},
23 SyntaxNode, SyntaxNodePtr, TextUnit, 26 SyntaxNode, SyntaxNodePtr, TextUnit,
@@ -25,8 +28,10 @@ use ra_syntax::{
25 28
26use crate::{ 29use crate::{
27 db::HirDatabase, semantics::PathResolution, Adt, Const, EnumVariant, Function, Local, MacroDef, 30 db::HirDatabase, semantics::PathResolution, Adt, Const, EnumVariant, Function, Local, MacroDef,
28 ModPath, ModuleDef, Path, PathKind, Static, Struct, Trait, Type, TypeAlias, TypeParam, 31 ModPath, ModuleDef, Path, PathKind, Static, Struct, StructField, Trait, Type, TypeAlias,
32 TypeParam,
29}; 33};
34use ra_db::CrateId;
30 35
31/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of 36/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
32/// original source files. It should not be used inside the HIR itself. 37/// original source files. It should not be used inside the HIR itself.
@@ -164,23 +169,6 @@ impl SourceAnalyzer {
164 Some((struct_field.into(), local)) 169 Some((struct_field.into(), local))
165 } 170 }
166 171
167 pub(crate) fn resolve_record_literal(
168 &self,
169 db: &dyn HirDatabase,
170 record_lit: &ast::RecordLit,
171 ) -> Option<crate::VariantDef> {
172 let expr_id = self.expr_id(db, &record_lit.clone().into())?;
173 self.infer.as_ref()?.variant_resolution_for_expr(expr_id).map(|it| it.into())
174 }
175
176 pub(crate) fn resolve_record_pattern(
177 &self,
178 record_pat: &ast::RecordPat,
179 ) -> Option<crate::VariantDef> {
180 let pat_id = self.pat_id(&record_pat.clone().into())?;
181 self.infer.as_ref()?.variant_resolution_for_pat(pat_id).map(|it| it.into())
182 }
183
184 pub(crate) fn resolve_macro_call( 172 pub(crate) fn resolve_macro_call(
185 &self, 173 &self,
186 db: &dyn HirDatabase, 174 db: &dyn HirDatabase,
@@ -231,6 +219,68 @@ impl SourceAnalyzer {
231 resolve_hir_path(db, &self.resolver, &hir_path) 219 resolve_hir_path(db, &self.resolver, &hir_path)
232 } 220 }
233 221
222 pub(crate) fn record_literal_missing_fields(
223 &self,
224 db: &dyn HirDatabase,
225 literal: &ast::RecordLit,
226 ) -> Option<Vec<(StructField, Type)>> {
227 let krate = self.resolver.krate()?;
228 let body = self.body.as_ref()?;
229 let infer = self.infer.as_ref()?;
230
231 let expr_id = self.expr_id(db, &literal.clone().into())?;
232 let substs = match &infer.type_of_expr[expr_id] {
233 Ty::Apply(a_ty) => &a_ty.parameters,
234 _ => return None,
235 };
236
237 let (variant, missing_fields, _exhaustive) =
238 record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
239 let res = self.missing_fields(db, krate, substs, variant, missing_fields);
240 Some(res)
241 }
242
243 pub(crate) fn record_pattern_missing_fields(
244 &self,
245 db: &dyn HirDatabase,
246 pattern: &ast::RecordPat,
247 ) -> Option<Vec<(StructField, Type)>> {
248 let krate = self.resolver.krate()?;
249 let body = self.body.as_ref()?;
250 let infer = self.infer.as_ref()?;
251
252 let pat_id = self.pat_id(&pattern.clone().into())?;
253 let substs = match &infer.type_of_pat[pat_id] {
254 Ty::Apply(a_ty) => &a_ty.parameters,
255 _ => return None,
256 };
257
258 let (variant, missing_fields) =
259 record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;
260 let res = self.missing_fields(db, krate, substs, variant, missing_fields);
261 Some(res)
262 }
263
264 fn missing_fields(
265 &self,
266 db: &dyn HirDatabase,
267 krate: CrateId,
268 substs: &Substs,
269 variant: VariantId,
270 missing_fields: Vec<LocalStructFieldId>,
271 ) -> Vec<(StructField, Type)> {
272 let field_types = db.field_types(variant);
273
274 missing_fields
275 .into_iter()
276 .map(|local_id| {
277 let field = StructFieldId { parent: variant, local_id };
278 let ty = field_types[local_id].clone().subst(substs);
279 (field.into(), Type::new_with_resolver_inner(db, krate, &self.resolver, ty))
280 })
281 .collect()
282 }
283
234 pub(crate) fn expand( 284 pub(crate) fn expand(
235 &self, 285 &self,
236 db: &dyn HirDatabase, 286 db: &dyn HirDatabase,
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 28c570c76..8d4b8b0f0 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -672,8 +672,7 @@ impl ExprCollector<'_> {
672 } 672 }
673 673
674 // FIXME: implement 674 // FIXME: implement
675 ast::Pat::BoxPat(_) => Pat::Missing, 675 ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
676 ast::Pat::RangePat(_) => Pat::Missing,
677 }; 676 };
678 let ptr = AstPtr::new(&pat); 677 let ptr = AstPtr::new(&pat);
679 self.alloc_pat(pattern, Either::Left(ptr)) 678 self.alloc_pat(pattern, Either::Left(ptr))
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index bd32ac20a..2d27bbdf8 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -7,6 +7,11 @@
7//! Note that `hir_def` is a work in progress, so not all of the above is 7//! Note that `hir_def` is a work in progress, so not all of the above is
8//! actually true. 8//! actually true.
9 9
10#[allow(unused)]
11macro_rules! eprintln {
12 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
13}
14
10pub mod db; 15pub mod db;
11 16
12pub mod attr; 17pub mod attr;
diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs
index 102fdb13d..01cc392db 100644
--- a/crates/ra_hir_def/src/type_ref.rs
+++ b/crates/ra_hir_def/src/type_ref.rs
@@ -93,7 +93,11 @@ impl TypeRef {
93 } 93 }
94 ast::TypeRef::PlaceholderType(_inner) => TypeRef::Placeholder, 94 ast::TypeRef::PlaceholderType(_inner) => TypeRef::Placeholder,
95 ast::TypeRef::FnPointerType(inner) => { 95 ast::TypeRef::FnPointerType(inner) => {
96 let ret_ty = TypeRef::from_ast_opt(inner.ret_type().and_then(|rt| rt.type_ref())); 96 let ret_ty = inner
97 .ret_type()
98 .and_then(|rt| rt.type_ref())
99 .map(TypeRef::from_ast)
100 .unwrap_or_else(|| TypeRef::Tuple(Vec::new()));
97 let mut params = if let Some(pl) = inner.param_list() { 101 let mut params = if let Some(pl) = inner.param_list() {
98 pl.params().map(|p| p.ascribed_type()).map(TypeRef::from_ast_opt).collect() 102 pl.params().map(|p| p.ascribed_type()).map(TypeRef::from_ast_opt).collect()
99 } else { 103 } else {
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs
index 79aea5806..bb45b0f1d 100644
--- a/crates/ra_hir_expand/src/builtin_derive.rs
+++ b/crates/ra_hir_expand/src/builtin_derive.rs
@@ -73,9 +73,9 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, mbe::ExpandError> {
73 let node = item.syntax(); 73 let node = item.syntax();
74 let (name, params) = match_ast! { 74 let (name, params) = match_ast! {
75 match node { 75 match node {
76 ast::StructDef(it) => { (it.name(), it.type_param_list()) }, 76 ast::StructDef(it) => (it.name(), it.type_param_list()),
77 ast::EnumDef(it) => { (it.name(), it.type_param_list()) }, 77 ast::EnumDef(it) => (it.name(), it.type_param_list()),
78 ast::UnionDef(it) => { (it.name(), it.type_param_list()) }, 78 ast::UnionDef(it) => (it.name(), it.type_param_list()),
79 _ => { 79 _ => {
80 debug!("unexpected node is {:?}", node); 80 debug!("unexpected node is {:?}", node);
81 return Err(mbe::ExpandError::ConversionError) 81 return Err(mbe::ExpandError::ConversionError)
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 5a58d70cf..9a4a7aa6f 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -9,6 +9,7 @@ doctest = false
9 9
10[dependencies] 10[dependencies]
11arrayvec = "0.5.1" 11arrayvec = "0.5.1"
12smallvec = "1.2.0"
12ena = "0.13.1" 13ena = "0.13.1"
13log = "0.4.8" 14log = "0.4.8"
14rustc-hash = "1.1.0" 15rustc-hash = "1.1.0"
@@ -23,9 +24,9 @@ ra_prof = { path = "../ra_prof" }
23ra_syntax = { path = "../ra_syntax" } 24ra_syntax = { path = "../ra_syntax" }
24test_utils = { path = "../test_utils" } 25test_utils = { path = "../test_utils" }
25 26
26chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "177d71340acc7a7204a33115fc63075d86452179" } 27chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" }
27chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "177d71340acc7a7204a33115fc63075d86452179" } 28chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" }
28chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "177d71340acc7a7204a33115fc63075d86452179" } 29chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" }
29 30
30[dev-dependencies] 31[dev-dependencies]
31insta = "0.15.0" 32insta = "0.15.0"
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/_match.rs
new file mode 100644
index 000000000..f29a25505
--- /dev/null
+++ b/crates/ra_hir_ty/src/_match.rs
@@ -0,0 +1,1411 @@
1//! This module implements match statement exhaustiveness checking and usefulness checking
2//! for match arms.
3//!
4//! It is modeled on the rustc module `librustc_mir_build::hair::pattern::_match`, which
5//! contains very detailed documentation about the algorithms used here. I've duplicated
6//! most of that documentation below.
7//!
8//! This file includes the logic for exhaustiveness and usefulness checking for
9//! pattern-matching. Specifically, given a list of patterns for a type, we can
10//! tell whether:
11//! (a) the patterns cover every possible constructor for the type [exhaustiveness]
12//! (b) each pattern is necessary [usefulness]
13//!
14//! The algorithm implemented here is a modified version of the one described in:
15//! http://moscova.inria.fr/~maranget/papers/warn/index.html
16//! However, to save future implementors from reading the original paper, we
17//! summarise the algorithm here to hopefully save time and be a little clearer
18//! (without being so rigorous).
19//!
20//! The core of the algorithm revolves about a "usefulness" check. In particular, we
21//! are trying to compute a predicate `U(P, p)` where `P` is a list of patterns (we refer to this as
22//! a matrix). `U(P, p)` represents whether, given an existing list of patterns
23//! `P_1 ..= P_m`, adding a new pattern `p` will be "useful" (that is, cover previously-
24//! uncovered values of the type).
25//!
26//! If we have this predicate, then we can easily compute both exhaustiveness of an
27//! entire set of patterns and the individual usefulness of each one.
28//! (a) the set of patterns is exhaustive iff `U(P, _)` is false (i.e., adding a wildcard
29//! match doesn't increase the number of values we're matching)
30//! (b) a pattern `P_i` is not useful if `U(P[0..=(i-1), P_i)` is false (i.e., adding a
31//! pattern to those that have come before it doesn't increase the number of values
32//! we're matching).
33//!
34//! During the course of the algorithm, the rows of the matrix won't just be individual patterns,
35//! but rather partially-deconstructed patterns in the form of a list of patterns. The paper
36//! calls those pattern-vectors, and we will call them pattern-stacks. The same holds for the
37//! new pattern `p`.
38//!
39//! For example, say we have the following:
40//! ```
41//! // x: (Option<bool>, Result<()>)
42//! match x {
43//! (Some(true), _) => {}
44//! (None, Err(())) => {}
45//! (None, Err(_)) => {}
46//! }
47//! ```
48//! Here, the matrix `P` starts as:
49//! [
50//! [(Some(true), _)],
51//! [(None, Err(()))],
52//! [(None, Err(_))],
53//! ]
54//! We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering
55//! `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because
56//! all the values it covers are already covered by row 2.
57//!
58//! A list of patterns can be thought of as a stack, because we are mainly interested in the top of
59//! the stack at any given point, and we can pop or apply constructors to get new pattern-stacks.
60//! To match the paper, the top of the stack is at the beginning / on the left.
61//!
62//! There are two important operations on pattern-stacks necessary to understand the algorithm:
63//! 1. We can pop a given constructor off the top of a stack. This operation is called
64//! `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or
65//! `None`) and `p` a pattern-stack.
66//! If the pattern on top of the stack can cover `c`, this removes the constructor and
67//! pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns.
68//! Otherwise the pattern-stack is discarded.
69//! This essentially filters those pattern-stacks whose top covers the constructor `c` and
70//! discards the others.
71//!
72//! For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we
73//! pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the
74//! `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get
75//! nothing back.
76//!
77//! This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1`
78//! on top of the stack, and we have four cases:
79//! 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We
80//! push onto the stack the arguments of this constructor, and return the result:
81//! r_1, .., r_a, p_2, .., p_n
82//! 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠ c'`. We discard the current stack and
83//! return nothing.
84//! 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has
85//! arguments (its arity), and return the resulting stack:
86//! _, .., _, p_2, .., p_n
87//! 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
88//! stack:
89//! S(c, (r_1, p_2, .., p_n))
90//! S(c, (r_2, p_2, .., p_n))
91//!
92//! 2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is
93//! a pattern-stack.
94//! This is used when we know there are missing constructor cases, but there might be
95//! existing wildcard patterns, so to check the usefulness of the matrix, we have to check
96//! all its *other* components.
97//!
98//! It is computed as follows. We look at the pattern `p_1` on top of the stack,
99//! and we have three cases:
100//! 1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing.
101//! 1.2. `p_1 = _`. We return the rest of the stack:
102//! p_2, .., p_n
103//! 1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting
104//! stack.
105//! D((r_1, p_2, .., p_n))
106//! D((r_2, p_2, .., p_n))
107//!
108//! Note that the OR-patterns are not always used directly in Rust, but are used to derive the
109//! exhaustive integer matching rules, so they're written here for posterity.
110//!
111//! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by
112//! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with
113//! the given constructor, and popping a wildcard keeps those rows that start with a wildcard.
114//!
115//!
116//! The algorithm for computing `U`
117//! -------------------------------
118//! The algorithm is inductive (on the number of columns: i.e., components of tuple patterns).
119//! That means we're going to check the components from left-to-right, so the algorithm
120//! operates principally on the first component of the matrix and new pattern-stack `p`.
121//! This algorithm is realised in the `is_useful` function.
122//!
123//! Base case. (`n = 0`, i.e., an empty tuple pattern)
124//! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`),
125//! then `U(P, p)` is false.
126//! - Otherwise, `P` must be empty, so `U(P, p)` is true.
127//!
128//! Inductive step. (`n > 0`, i.e., whether there's at least one column
129//! [which may then be expanded into further columns later])
130//! We're going to match on the top of the new pattern-stack, `p_1`.
131//! - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern.
132//! Then, the usefulness of `p_1` can be reduced to whether it is useful when
133//! we ignore all the patterns in the first column of `P` that involve other constructors.
134//! This is where `S(c, P)` comes in:
135//! `U(P, p) := U(S(c, P), S(c, p))`
136//! This special case is handled in `is_useful_specialized`.
137//!
138//! For example, if `P` is:
139//! [
140//! [Some(true), _],
141//! [None, 0],
142//! ]
143//! and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only
144//! matches values that row 2 doesn't. For row 1 however, we need to dig into the
145//! arguments of `Some` to know whether some new value is covered. So we compute
146//! `U([[true, _]], [false, 0])`.
147//!
148//! - If `p_1 == _`, then we look at the list of constructors that appear in the first
149//! component of the rows of `P`:
150//! + If there are some constructors that aren't present, then we might think that the
151//! wildcard `_` is useful, since it covers those constructors that weren't covered
152//! before.
153//! That's almost correct, but only works if there were no wildcards in those first
154//! components. So we need to check that `p` is useful with respect to the rows that
155//! start with a wildcard, if there are any. This is where `D` comes in:
156//! `U(P, p) := U(D(P), D(p))`
157//!
158//! For example, if `P` is:
159//! [
160//! [_, true, _],
161//! [None, false, 1],
162//! ]
163//! and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we
164//! only had row 2, we'd know that `p` is useful. However row 1 starts with a
165//! wildcard, so we need to check whether `U([[true, _]], [false, 1])`.
166//!
167//! + Otherwise, all possible constructors (for the relevant type) are present. In this
168//! case we must check whether the wildcard pattern covers any unmatched value. For
169//! that, we can think of the `_` pattern as a big OR-pattern that covers all
170//! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for
171//! example. The wildcard pattern is useful in this case if it is useful when
172//! specialized to one of the possible constructors. So we compute:
173//! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))`
174//!
175//! For example, if `P` is:
176//! [
177//! [Some(true), _],
178//! [None, false],
179//! ]
180//! and `p` is [_, false], both `None` and `Some` constructors appear in the first
181//! components of `P`. We will therefore try popping both constructors in turn: we
182//! compute U([[true, _]], [_, false]) for the `Some` constructor, and U([[false]],
183//! [false]) for the `None` constructor. The first case returns true, so we know that
184//! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched
185//! before.
186//!
187//! - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately:
188//! `U(P, p) := U(P, (r_1, p_2, .., p_n))
189//! || U(P, (r_2, p_2, .., p_n))`
190use std::sync::Arc;
191
192use smallvec::{smallvec, SmallVec};
193
194use crate::{
195 db::HirDatabase,
196 expr::{Body, Expr, Literal, Pat, PatId},
197 InferenceResult,
198};
199use hir_def::{adt::VariantData, EnumVariantId, VariantId};
200
201#[derive(Debug, Clone, Copy)]
202/// Either a pattern from the source code being analyzed, represented as
203/// as `PatId`, or a `Wild` pattern which is created as an intermediate
204/// step in the match checking algorithm and thus is not backed by a
205/// real `PatId`.
206///
207/// Note that it is totally valid for the `PatId` variant to contain
208/// a `PatId` which resolves to a `Wild` pattern, if that wild pattern
209/// exists in the source code being analyzed.
210enum PatIdOrWild {
211 PatId(PatId),
212 Wild,
213}
214
215impl PatIdOrWild {
216 fn as_pat(self, cx: &MatchCheckCtx) -> Pat {
217 match self {
218 PatIdOrWild::PatId(id) => cx.body.pats[id].clone(),
219 PatIdOrWild::Wild => Pat::Wild,
220 }
221 }
222
223 fn as_id(self) -> Option<PatId> {
224 match self {
225 PatIdOrWild::PatId(id) => Some(id),
226 PatIdOrWild::Wild => None,
227 }
228 }
229}
230
231impl From<PatId> for PatIdOrWild {
232 fn from(pat_id: PatId) -> Self {
233 Self::PatId(pat_id)
234 }
235}
236
237#[derive(Debug, Clone, Copy, PartialEq)]
238pub struct MatchCheckNotImplemented;
239
240/// The return type of `is_useful` is either an indication of usefulness
241/// of the match arm, or an error in the case the match statement
242/// is made up of types for which exhaustiveness checking is currently
243/// not completely implemented.
244///
245/// The `std::result::Result` type is used here rather than a custom enum
246/// to allow the use of `?`.
247pub type MatchCheckResult<T> = Result<T, MatchCheckNotImplemented>;
248
249#[derive(Debug)]
250/// A row in a Matrix.
251///
252/// This type is modeled from the struct of the same name in `rustc`.
253pub(crate) struct PatStack(PatStackInner);
254type PatStackInner = SmallVec<[PatIdOrWild; 2]>;
255
256impl PatStack {
257 pub(crate) fn from_pattern(pat_id: PatId) -> PatStack {
258 Self(smallvec!(pat_id.into()))
259 }
260
261 pub(crate) fn from_wild() -> PatStack {
262 Self(smallvec!(PatIdOrWild::Wild))
263 }
264
265 fn from_slice(slice: &[PatIdOrWild]) -> PatStack {
266 Self(SmallVec::from_slice(slice))
267 }
268
269 fn from_vec(v: PatStackInner) -> PatStack {
270 Self(v)
271 }
272
273 fn is_empty(&self) -> bool {
274 self.0.is_empty()
275 }
276
277 fn head(&self) -> PatIdOrWild {
278 self.0[0]
279 }
280
281 fn get_head(&self) -> Option<PatIdOrWild> {
282 self.0.first().copied()
283 }
284
285 fn to_tail(&self) -> PatStack {
286 Self::from_slice(&self.0[1..])
287 }
288
289 fn replace_head_with(&self, pat_ids: &[PatId]) -> PatStack {
290 let mut patterns: PatStackInner = smallvec![];
291 for pat in pat_ids {
292 patterns.push((*pat).into());
293 }
294 for pat in &self.0[1..] {
295 patterns.push(*pat);
296 }
297 PatStack::from_vec(patterns)
298 }
299
300 /// Computes `D(self)`.
301 ///
302 /// See the module docs and the associated documentation in rustc for details.
303 fn specialize_wildcard(&self, cx: &MatchCheckCtx) -> Option<PatStack> {
304 if matches!(self.head().as_pat(cx), Pat::Wild) {
305 Some(self.to_tail())
306 } else {
307 None
308 }
309 }
310
311 /// Computes `S(constructor, self)`.
312 ///
313 /// See the module docs and the associated documentation in rustc for details.
314 fn specialize_constructor(
315 &self,
316 cx: &MatchCheckCtx,
317 constructor: &Constructor,
318 ) -> MatchCheckResult<Option<PatStack>> {
319 let result = match (self.head().as_pat(cx), constructor) {
320 (Pat::Tuple(ref pat_ids), Constructor::Tuple { arity }) => {
321 debug_assert_eq!(
322 pat_ids.len(),
323 *arity,
324 "we type check before calling this code, so we should never hit this case",
325 );
326
327 Some(self.replace_head_with(pat_ids))
328 }
329 (Pat::Lit(lit_expr), Constructor::Bool(constructor_val)) => {
330 match cx.body.exprs[lit_expr] {
331 Expr::Literal(Literal::Bool(pat_val)) if *constructor_val == pat_val => {
332 Some(self.to_tail())
333 }
334 // it was a bool but the value doesn't match
335 Expr::Literal(Literal::Bool(_)) => None,
336 // perhaps this is actually unreachable given we have
337 // already checked that these match arms have the appropriate type?
338 _ => return Err(MatchCheckNotImplemented),
339 }
340 }
341 (Pat::Wild, constructor) => Some(self.expand_wildcard(cx, constructor)?),
342 (Pat::Path(_), Constructor::Enum(constructor)) => {
343 // enums with no associated data become `Pat::Path`
344 let pat_id = self.head().as_id().expect("we know this isn't a wild");
345 if !enum_variant_matches(cx, pat_id, *constructor) {
346 None
347 } else {
348 Some(self.to_tail())
349 }
350 }
351 (Pat::TupleStruct { args: ref pat_ids, .. }, Constructor::Enum(constructor)) => {
352 let pat_id = self.head().as_id().expect("we know this isn't a wild");
353 if !enum_variant_matches(cx, pat_id, *constructor) {
354 None
355 } else {
356 Some(self.replace_head_with(pat_ids))
357 }
358 }
359 (Pat::Or(_), _) => return Err(MatchCheckNotImplemented),
360 (_, _) => return Err(MatchCheckNotImplemented),
361 };
362
363 Ok(result)
364 }
365
366 /// A special case of `specialize_constructor` where the head of the pattern stack
367 /// is a Wild pattern.
368 ///
369 /// Replaces the Wild pattern at the head of the pattern stack with N Wild patterns
370 /// (N >= 0), where N is the arity of the given constructor.
371 fn expand_wildcard(
372 &self,
373 cx: &MatchCheckCtx,
374 constructor: &Constructor,
375 ) -> MatchCheckResult<PatStack> {
376 assert_eq!(
377 Pat::Wild,
378 self.head().as_pat(cx),
379 "expand_wildcard must only be called on PatStack with wild at head",
380 );
381
382 let mut patterns: PatStackInner = smallvec![];
383
384 for _ in 0..constructor.arity(cx)? {
385 patterns.push(PatIdOrWild::Wild);
386 }
387
388 for pat in &self.0[1..] {
389 patterns.push(*pat);
390 }
391
392 Ok(PatStack::from_vec(patterns))
393 }
394}
395
396#[derive(Debug)]
397/// A collection of PatStack.
398///
399/// This type is modeled from the struct of the same name in `rustc`.
400pub(crate) struct Matrix(Vec<PatStack>);
401
402impl Matrix {
403 pub(crate) fn empty() -> Self {
404 Self(vec![])
405 }
406
407 pub(crate) fn push(&mut self, cx: &MatchCheckCtx, row: PatStack) {
408 if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) {
409 // Or patterns are expanded here
410 for pat_id in pat_ids {
411 self.0.push(PatStack::from_pattern(pat_id));
412 }
413 } else {
414 self.0.push(row);
415 }
416 }
417
418 fn is_empty(&self) -> bool {
419 self.0.is_empty()
420 }
421
422 fn heads(&self) -> Vec<PatIdOrWild> {
423 self.0.iter().map(|p| p.head()).collect()
424 }
425
426 /// Computes `D(self)` for each contained PatStack.
427 ///
428 /// See the module docs and the associated documentation in rustc for details.
429 fn specialize_wildcard(&self, cx: &MatchCheckCtx) -> Self {
430 Self::collect(cx, self.0.iter().filter_map(|r| r.specialize_wildcard(cx)))
431 }
432
433 /// Computes `S(constructor, self)` for each contained PatStack.
434 ///
435 /// See the module docs and the associated documentation in rustc for details.
436 fn specialize_constructor(
437 &self,
438 cx: &MatchCheckCtx,
439 constructor: &Constructor,
440 ) -> MatchCheckResult<Self> {
441 let mut new_matrix = Matrix::empty();
442 for pat in &self.0 {
443 if let Some(pat) = pat.specialize_constructor(cx, constructor)? {
444 new_matrix.push(cx, pat);
445 }
446 }
447
448 Ok(new_matrix)
449 }
450
451 fn collect<T: IntoIterator<Item = PatStack>>(cx: &MatchCheckCtx, iter: T) -> Self {
452 let mut matrix = Matrix::empty();
453
454 for pat in iter {
455 // using push ensures we expand or-patterns
456 matrix.push(cx, pat);
457 }
458
459 matrix
460 }
461}
462
463#[derive(Clone, Debug, PartialEq)]
464/// An indication of the usefulness of a given match arm, where
465/// usefulness is defined as matching some patterns which were
466/// not matched by an prior match arms.
467///
468/// We may eventually need an `Unknown` variant here.
469pub enum Usefulness {
470 Useful,
471 NotUseful,
472}
473
474pub struct MatchCheckCtx<'a> {
475 pub body: Arc<Body>,
476 pub infer: Arc<InferenceResult>,
477 pub db: &'a dyn HirDatabase,
478}
479
480/// Given a set of patterns `matrix`, and pattern to consider `v`, determines
481/// whether `v` is useful. A pattern is useful if it covers cases which were
482/// not previously covered.
483///
484/// When calling this function externally (that is, not the recursive calls) it
485/// expected that you have already type checked the match arms. All patterns in
486/// matrix should be the same type as v, as well as they should all be the same
487/// type as the match expression.
488pub(crate) fn is_useful(
489 cx: &MatchCheckCtx,
490 matrix: &Matrix,
491 v: &PatStack,
492) -> MatchCheckResult<Usefulness> {
493 if v.is_empty() {
494 let result = if matrix.is_empty() { Usefulness::Useful } else { Usefulness::NotUseful };
495
496 return Ok(result);
497 }
498
499 if let Pat::Or(pat_ids) = v.head().as_pat(cx) {
500 let mut found_unimplemented = false;
501 let any_useful = pat_ids.iter().any(|&pat_id| {
502 let v = PatStack::from_pattern(pat_id);
503
504 match is_useful(cx, matrix, &v) {
505 Ok(Usefulness::Useful) => true,
506 Ok(Usefulness::NotUseful) => false,
507 _ => {
508 found_unimplemented = true;
509 false
510 }
511 }
512 });
513
514 return if any_useful {
515 Ok(Usefulness::Useful)
516 } else if found_unimplemented {
517 Err(MatchCheckNotImplemented)
518 } else {
519 Ok(Usefulness::NotUseful)
520 };
521 }
522
523 if let Some(constructor) = pat_constructor(cx, v.head())? {
524 let matrix = matrix.specialize_constructor(&cx, &constructor)?;
525 let v = v
526 .specialize_constructor(&cx, &constructor)?
527 .expect("we know this can't fail because we get the constructor from `v.head()` above");
528
529 is_useful(&cx, &matrix, &v)
530 } else {
531 // expanding wildcard
532 let mut used_constructors: Vec<Constructor> = vec![];
533 for pat in matrix.heads() {
534 if let Some(constructor) = pat_constructor(cx, pat)? {
535 used_constructors.push(constructor);
536 }
537 }
538
539 // We assume here that the first constructor is the "correct" type. Since we
540 // only care about the "type" of the constructor (i.e. if it is a bool we
541 // don't care about the value), this assumption should be valid as long as
542 // the match statement is well formed. We currently uphold this invariant by
543 // filtering match arms before calling `is_useful`, only passing in match arms
544 // whose type matches the type of the match expression.
545 match &used_constructors.first() {
546 Some(constructor) if all_constructors_covered(&cx, constructor, &used_constructors) => {
547 // If all constructors are covered, then we need to consider whether
548 // any values are covered by this wildcard.
549 //
550 // For example, with matrix '[[Some(true)], [None]]', all
551 // constructors are covered (`Some`/`None`), so we need
552 // to perform specialization to see that our wildcard will cover
553 // the `Some(false)` case.
554 //
555 // Here we create a constructor for each variant and then check
556 // usefulness after specializing for that constructor.
557 let mut found_unimplemented = false;
558 for constructor in constructor.all_constructors(cx) {
559 let matrix = matrix.specialize_constructor(&cx, &constructor)?;
560 let v = v.expand_wildcard(&cx, &constructor)?;
561
562 match is_useful(&cx, &matrix, &v) {
563 Ok(Usefulness::Useful) => return Ok(Usefulness::Useful),
564 Ok(Usefulness::NotUseful) => continue,
565 _ => found_unimplemented = true,
566 };
567 }
568
569 if found_unimplemented {
570 Err(MatchCheckNotImplemented)
571 } else {
572 Ok(Usefulness::NotUseful)
573 }
574 }
575 _ => {
576 // Either not all constructors are covered, or the only other arms
577 // are wildcards. Either way, this pattern is useful if it is useful
578 // when compared to those arms with wildcards.
579 let matrix = matrix.specialize_wildcard(&cx);
580 let v = v.to_tail();
581
582 is_useful(&cx, &matrix, &v)
583 }
584 }
585 }
586}
587
588#[derive(Debug, Clone, Copy)]
589/// Similar to TypeCtor, but includes additional information about the specific
590/// value being instantiated. For example, TypeCtor::Bool doesn't contain the
591/// boolean value.
592enum Constructor {
593 Bool(bool),
594 Tuple { arity: usize },
595 Enum(EnumVariantId),
596}
597
598impl Constructor {
599 fn arity(&self, cx: &MatchCheckCtx) -> MatchCheckResult<usize> {
600 let arity = match self {
601 Constructor::Bool(_) => 0,
602 Constructor::Tuple { arity } => *arity,
603 Constructor::Enum(e) => {
604 match cx.db.enum_data(e.parent).variants[e.local_id].variant_data.as_ref() {
605 VariantData::Tuple(struct_field_data) => struct_field_data.len(),
606 VariantData::Unit => 0,
607 _ => return Err(MatchCheckNotImplemented),
608 }
609 }
610 };
611
612 Ok(arity)
613 }
614
615 fn all_constructors(&self, cx: &MatchCheckCtx) -> Vec<Constructor> {
616 match self {
617 Constructor::Bool(_) => vec![Constructor::Bool(true), Constructor::Bool(false)],
618 Constructor::Tuple { .. } => vec![*self],
619 Constructor::Enum(e) => cx
620 .db
621 .enum_data(e.parent)
622 .variants
623 .iter()
624 .map(|(local_id, _)| {
625 Constructor::Enum(EnumVariantId { parent: e.parent, local_id })
626 })
627 .collect(),
628 }
629 }
630}
631
632/// Returns the constructor for the given pattern. Should only return None
633/// in the case of a Wild pattern.
634fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> {
635 let res = match pat.as_pat(cx) {
636 Pat::Wild => None,
637 Pat::Tuple(pats) => Some(Constructor::Tuple { arity: pats.len() }),
638 Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] {
639 Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)),
640 _ => return Err(MatchCheckNotImplemented),
641 },
642 Pat::TupleStruct { .. } | Pat::Path(_) => {
643 let pat_id = pat.as_id().expect("we already know this pattern is not a wild");
644 let variant_id =
645 cx.infer.variant_resolution_for_pat(pat_id).ok_or(MatchCheckNotImplemented)?;
646 match variant_id {
647 VariantId::EnumVariantId(enum_variant_id) => {
648 Some(Constructor::Enum(enum_variant_id))
649 }
650 _ => return Err(MatchCheckNotImplemented),
651 }
652 }
653 _ => return Err(MatchCheckNotImplemented),
654 };
655
656 Ok(res)
657}
658
659fn all_constructors_covered(
660 cx: &MatchCheckCtx,
661 constructor: &Constructor,
662 used_constructors: &[Constructor],
663) -> bool {
664 match constructor {
665 Constructor::Tuple { arity } => {
666 used_constructors.iter().any(|constructor| match constructor {
667 Constructor::Tuple { arity: used_arity } => arity == used_arity,
668 _ => false,
669 })
670 }
671 Constructor::Bool(_) => {
672 if used_constructors.is_empty() {
673 return false;
674 }
675
676 let covers_true =
677 used_constructors.iter().any(|c| matches!(c, Constructor::Bool(true)));
678 let covers_false =
679 used_constructors.iter().any(|c| matches!(c, Constructor::Bool(false)));
680
681 covers_true && covers_false
682 }
683 Constructor::Enum(e) => cx.db.enum_data(e.parent).variants.iter().all(|(id, _)| {
684 for constructor in used_constructors {
685 if let Constructor::Enum(e) = constructor {
686 if id == e.local_id {
687 return true;
688 }
689 }
690 }
691
692 false
693 }),
694 }
695}
696
697fn enum_variant_matches(cx: &MatchCheckCtx, pat_id: PatId, enum_variant_id: EnumVariantId) -> bool {
698 Some(enum_variant_id.into()) == cx.infer.variant_resolution_for_pat(pat_id)
699}
700
701#[cfg(test)]
702mod tests {
703 pub(super) use insta::assert_snapshot;
704 pub(super) use ra_db::fixture::WithFixture;
705
706 pub(super) use crate::test_db::TestDB;
707
708 pub(super) fn check_diagnostic_message(content: &str) -> String {
709 TestDB::with_single_file(content).0.diagnostics().0
710 }
711
712 pub(super) fn check_diagnostic(content: &str) {
713 let diagnostic_count = TestDB::with_single_file(content).0.diagnostics().1;
714
715 assert_eq!(1, diagnostic_count, "no diagnostic reported");
716 }
717
718 pub(super) fn check_no_diagnostic(content: &str) {
719 let diagnostic_count = TestDB::with_single_file(content).0.diagnostics().1;
720
721 assert_eq!(0, diagnostic_count, "expected no diagnostic, found one");
722 }
723
724 #[test]
725 fn empty_tuple_no_arms_diagnostic_message() {
726 let content = r"
727 fn test_fn() {
728 match () {
729 }
730 }
731 ";
732
733 assert_snapshot!(
734 check_diagnostic_message(content),
735 @"\"()\": Missing match arm\n"
736 );
737 }
738
739 #[test]
740 fn empty_tuple_no_arms() {
741 let content = r"
742 fn test_fn() {
743 match () {
744 }
745 }
746 ";
747
748 check_diagnostic(content);
749 }
750
751 #[test]
752 fn empty_tuple_wild() {
753 let content = r"
754 fn test_fn() {
755 match () {
756 _ => {}
757 }
758 }
759 ";
760
761 check_no_diagnostic(content);
762 }
763
764 #[test]
765 fn empty_tuple_no_diagnostic() {
766 let content = r"
767 fn test_fn() {
768 match () {
769 () => {}
770 }
771 }
772 ";
773
774 check_no_diagnostic(content);
775 }
776
777 #[test]
778 fn tuple_of_empty_tuple_no_arms() {
779 let content = r"
780 fn test_fn() {
781 match (()) {
782 }
783 }
784 ";
785
786 check_diagnostic(content);
787 }
788
789 #[test]
790 fn tuple_of_empty_tuple_no_diagnostic() {
791 let content = r"
792 fn test_fn() {
793 match (()) {
794 (()) => {}
795 }
796 }
797 ";
798
799 check_no_diagnostic(content);
800 }
801
802 #[test]
803 fn tuple_of_two_empty_tuple_no_arms() {
804 let content = r"
805 fn test_fn() {
806 match ((), ()) {
807 }
808 }
809 ";
810
811 check_diagnostic(content);
812 }
813
814 #[test]
815 fn tuple_of_two_empty_tuple_no_diagnostic() {
816 let content = r"
817 fn test_fn() {
818 match ((), ()) {
819 ((), ()) => {}
820 }
821 }
822 ";
823
824 check_no_diagnostic(content);
825 }
826
827 #[test]
828 fn bool_no_arms() {
829 let content = r"
830 fn test_fn() {
831 match false {
832 }
833 }
834 ";
835
836 check_diagnostic(content);
837 }
838
839 #[test]
840 fn bool_missing_arm() {
841 let content = r"
842 fn test_fn() {
843 match false {
844 true => {}
845 }
846 }
847 ";
848
849 check_diagnostic(content);
850 }
851
852 #[test]
853 fn bool_no_diagnostic() {
854 let content = r"
855 fn test_fn() {
856 match false {
857 true => {}
858 false => {}
859 }
860 }
861 ";
862
863 check_no_diagnostic(content);
864 }
865
866 #[test]
867 fn tuple_of_bools_no_arms() {
868 let content = r"
869 fn test_fn() {
870 match (false, true) {
871 }
872 }
873 ";
874
875 check_diagnostic(content);
876 }
877
878 #[test]
879 fn tuple_of_bools_missing_arms() {
880 let content = r"
881 fn test_fn() {
882 match (false, true) {
883 (true, true) => {},
884 }
885 }
886 ";
887
888 check_diagnostic(content);
889 }
890
891 #[test]
892 fn tuple_of_bools_missing_arm() {
893 let content = r"
894 fn test_fn() {
895 match (false, true) {
896 (false, true) => {},
897 (false, false) => {},
898 (true, false) => {},
899 }
900 }
901 ";
902
903 check_diagnostic(content);
904 }
905
906 #[test]
907 fn tuple_of_bools_with_wilds() {
908 let content = r"
909 fn test_fn() {
910 match (false, true) {
911 (false, _) => {},
912 (true, false) => {},
913 (_, true) => {},
914 }
915 }
916 ";
917
918 check_no_diagnostic(content);
919 }
920
921 #[test]
922 fn tuple_of_bools_no_diagnostic() {
923 let content = r"
924 fn test_fn() {
925 match (false, true) {
926 (true, true) => {},
927 (true, false) => {},
928 (false, true) => {},
929 (false, false) => {},
930 }
931 }
932 ";
933
934 check_no_diagnostic(content);
935 }
936
937 #[test]
938 fn tuple_of_bools_binding_missing_arms() {
939 let content = r"
940 fn test_fn() {
941 match (false, true) {
942 (true, _x) => {},
943 }
944 }
945 ";
946
947 check_diagnostic(content);
948 }
949
950 #[test]
951 fn tuple_of_bools_binding_no_diagnostic() {
952 let content = r"
953 fn test_fn() {
954 match (false, true) {
955 (true, _x) => {},
956 (false, true) => {},
957 (false, false) => {},
958 }
959 }
960 ";
961
962 check_no_diagnostic(content);
963 }
964
965 #[test]
966 fn tuple_of_tuple_and_bools_no_arms() {
967 let content = r"
968 fn test_fn() {
969 match (false, ((), false)) {
970 }
971 }
972 ";
973
974 check_diagnostic(content);
975 }
976
977 #[test]
978 fn tuple_of_tuple_and_bools_missing_arms() {
979 let content = r"
980 fn test_fn() {
981 match (false, ((), false)) {
982 (true, ((), true)) => {},
983 }
984 }
985 ";
986
987 check_diagnostic(content);
988 }
989
990 #[test]
991 fn tuple_of_tuple_and_bools_no_diagnostic() {
992 let content = r"
993 fn test_fn() {
994 match (false, ((), false)) {
995 (true, ((), true)) => {},
996 (true, ((), false)) => {},
997 (false, ((), true)) => {},
998 (false, ((), false)) => {},
999 }
1000 }
1001 ";
1002
1003 check_no_diagnostic(content);
1004 }
1005
1006 #[test]
1007 fn tuple_of_tuple_and_bools_wildcard_missing_arms() {
1008 let content = r"
1009 fn test_fn() {
1010 match (false, ((), false)) {
1011 (true, _) => {},
1012 }
1013 }
1014 ";
1015
1016 check_diagnostic(content);
1017 }
1018
1019 #[test]
1020 fn tuple_of_tuple_and_bools_wildcard_no_diagnostic() {
1021 let content = r"
1022 fn test_fn() {
1023 match (false, ((), false)) {
1024 (true, ((), true)) => {},
1025 (true, ((), false)) => {},
1026 (false, _) => {},
1027 }
1028 }
1029 ";
1030
1031 check_no_diagnostic(content);
1032 }
1033
1034 #[test]
1035 fn enum_no_arms() {
1036 let content = r"
1037 enum Either {
1038 A,
1039 B,
1040 }
1041 fn test_fn() {
1042 match Either::A {
1043 }
1044 }
1045 ";
1046
1047 check_diagnostic(content);
1048 }
1049
1050 #[test]
1051 fn enum_missing_arms() {
1052 let content = r"
1053 enum Either {
1054 A,
1055 B,
1056 }
1057 fn test_fn() {
1058 match Either::B {
1059 Either::A => {},
1060 }
1061 }
1062 ";
1063
1064 check_diagnostic(content);
1065 }
1066
1067 #[test]
1068 fn enum_no_diagnostic() {
1069 let content = r"
1070 enum Either {
1071 A,
1072 B,
1073 }
1074 fn test_fn() {
1075 match Either::B {
1076 Either::A => {},
1077 Either::B => {},
1078 }
1079 }
1080 ";
1081
1082 check_no_diagnostic(content);
1083 }
1084
1085 #[test]
1086 fn enum_ref_missing_arms() {
1087 let content = r"
1088 enum Either {
1089 A,
1090 B,
1091 }
1092 fn test_fn() {
1093 match &Either::B {
1094 Either::A => {},
1095 }
1096 }
1097 ";
1098
1099 check_diagnostic(content);
1100 }
1101
1102 #[test]
1103 fn enum_ref_no_diagnostic() {
1104 let content = r"
1105 enum Either {
1106 A,
1107 B,
1108 }
1109 fn test_fn() {
1110 match &Either::B {
1111 Either::A => {},
1112 Either::B => {},
1113 }
1114 }
1115 ";
1116
1117 check_no_diagnostic(content);
1118 }
1119
1120 #[test]
1121 fn enum_containing_bool_no_arms() {
1122 let content = r"
1123 enum Either {
1124 A(bool),
1125 B,
1126 }
1127 fn test_fn() {
1128 match Either::B {
1129 }
1130 }
1131 ";
1132
1133 check_diagnostic(content);
1134 }
1135
1136 #[test]
1137 fn enum_containing_bool_missing_arms() {
1138 let content = r"
1139 enum Either {
1140 A(bool),
1141 B,
1142 }
1143 fn test_fn() {
1144 match Either::B {
1145 Either::A(true) => (),
1146 Either::B => (),
1147 }
1148 }
1149 ";
1150
1151 check_diagnostic(content);
1152 }
1153
1154 #[test]
1155 fn enum_containing_bool_no_diagnostic() {
1156 let content = r"
1157 enum Either {
1158 A(bool),
1159 B,
1160 }
1161 fn test_fn() {
1162 match Either::B {
1163 Either::A(true) => (),
1164 Either::A(false) => (),
1165 Either::B => (),
1166 }
1167 }
1168 ";
1169
1170 check_no_diagnostic(content);
1171 }
1172
1173 #[test]
1174 fn enum_containing_bool_with_wild_no_diagnostic() {
1175 let content = r"
1176 enum Either {
1177 A(bool),
1178 B,
1179 }
1180 fn test_fn() {
1181 match Either::B {
1182 Either::B => (),
1183 _ => (),
1184 }
1185 }
1186 ";
1187
1188 check_no_diagnostic(content);
1189 }
1190
1191 #[test]
1192 fn enum_containing_bool_with_wild_2_no_diagnostic() {
1193 let content = r"
1194 enum Either {
1195 A(bool),
1196 B,
1197 }
1198 fn test_fn() {
1199 match Either::B {
1200 Either::A(_) => (),
1201 Either::B => (),
1202 }
1203 }
1204 ";
1205
1206 check_no_diagnostic(content);
1207 }
1208
1209 #[test]
1210 fn enum_different_sizes_missing_arms() {
1211 let content = r"
1212 enum Either {
1213 A(bool),
1214 B(bool, bool),
1215 }
1216 fn test_fn() {
1217 match Either::A(false) {
1218 Either::A(_) => (),
1219 Either::B(false, _) => (),
1220 }
1221 }
1222 ";
1223
1224 check_diagnostic(content);
1225 }
1226
1227 #[test]
1228 fn enum_different_sizes_no_diagnostic() {
1229 let content = r"
1230 enum Either {
1231 A(bool),
1232 B(bool, bool),
1233 }
1234 fn test_fn() {
1235 match Either::A(false) {
1236 Either::A(_) => (),
1237 Either::B(true, _) => (),
1238 Either::B(false, _) => (),
1239 }
1240 }
1241 ";
1242
1243 check_no_diagnostic(content);
1244 }
1245
1246 #[test]
1247 fn or_no_diagnostic() {
1248 let content = r"
1249 enum Either {
1250 A(bool),
1251 B(bool, bool),
1252 }
1253 fn test_fn() {
1254 match Either::A(false) {
1255 Either::A(true) | Either::A(false) => (),
1256 Either::B(true, _) => (),
1257 Either::B(false, _) => (),
1258 }
1259 }
1260 ";
1261
1262 check_no_diagnostic(content);
1263 }
1264
1265 #[test]
1266 fn tuple_of_enum_no_diagnostic() {
1267 let content = r"
1268 enum Either {
1269 A(bool),
1270 B(bool, bool),
1271 }
1272 enum Either2 {
1273 C,
1274 D,
1275 }
1276 fn test_fn() {
1277 match (Either::A(false), Either2::C) {
1278 (Either::A(true), _) | (Either::A(false), _) => (),
1279 (Either::B(true, _), Either2::C) => (),
1280 (Either::B(false, _), Either2::C) => (),
1281 (Either::B(_, _), Either2::D) => (),
1282 }
1283 }
1284 ";
1285
1286 check_no_diagnostic(content);
1287 }
1288
1289 #[test]
1290 fn mismatched_types() {
1291 let content = r"
1292 enum Either {
1293 A,
1294 B,
1295 }
1296 enum Either2 {
1297 C,
1298 D,
1299 }
1300 fn test_fn() {
1301 match Either::A {
1302 Either2::C => (),
1303 Either2::D => (),
1304 }
1305 }
1306 ";
1307
1308 // Match arms with the incorrect type are filtered out.
1309 check_diagnostic(content);
1310 }
1311
1312 #[test]
1313 fn mismatched_types_with_different_arity() {
1314 let content = r"
1315 fn test_fn() {
1316 match (true, false) {
1317 (true, false, true) => (),
1318 (true) => (),
1319 }
1320 }
1321 ";
1322
1323 // Match arms with the incorrect type are filtered out.
1324 check_diagnostic(content);
1325 }
1326
1327 #[test]
1328 fn enum_not_in_scope() {
1329 let content = r"
1330 fn test_fn() {
1331 match Foo::Bar {
1332 Foo::Baz => (),
1333 }
1334 }
1335 ";
1336
1337 // The enum is not in scope so we don't perform exhaustiveness
1338 // checking, but we want to be sure we don't panic here (and
1339 // we don't create a diagnostic).
1340 check_no_diagnostic(content);
1341 }
1342}
1343
1344#[cfg(test)]
1345mod false_negatives {
1346 //! The implementation of match checking here is a work in progress. As we roll this out, we
1347 //! prefer false negatives to false positives (ideally there would be no false positives). This
1348 //! test module should document known false negatives. Eventually we will have a complete
1349 //! implementation of match checking and this module will be empty.
1350 //!
1351 //! The reasons for documenting known false negatives:
1352 //!
1353 //! 1. It acts as a backlog of work that can be done to improve the behavior of the system.
1354 //! 2. It ensures the code doesn't panic when handling these cases.
1355
1356 use super::tests::*;
1357
1358 #[test]
1359 fn integers() {
1360 let content = r"
1361 fn test_fn() {
1362 match 5 {
1363 10 => (),
1364 11..20 => (),
1365 }
1366 }
1367 ";
1368
1369 // This is a false negative.
1370 // We don't currently check integer exhaustiveness.
1371 check_no_diagnostic(content);
1372 }
1373
1374 #[test]
1375 fn enum_record() {
1376 let content = r"
1377 enum Either {
1378 A { foo: u32 },
1379 B,
1380 }
1381 fn test_fn() {
1382 match Either::B {
1383 Either::A { foo: 5 } => (),
1384 }
1385 }
1386 ";
1387
1388 // This is a false negative.
1389 // We don't currently handle enum record types.
1390 check_no_diagnostic(content);
1391 }
1392
1393 #[test]
1394 fn internal_or() {
1395 let content = r"
1396 fn test_fn() {
1397 enum Either {
1398 A(bool),
1399 B,
1400 }
1401 match Either::B {
1402 Either::A(true | false) => (),
1403 }
1404 }
1405 ";
1406
1407 // This is a false negative.
1408 // We do not currently handle patterns with internal `or`s.
1409 check_no_diagnostic(content);
1410 }
1411}
diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs
index 53e81e85d..d91c21e24 100644
--- a/crates/ra_hir_ty/src/autoderef.rs
+++ b/crates/ra_hir_ty/src/autoderef.rs
@@ -14,7 +14,7 @@ use crate::{
14 db::HirDatabase, 14 db::HirDatabase,
15 traits::{InEnvironment, Solution}, 15 traits::{InEnvironment, Solution},
16 utils::generics, 16 utils::generics,
17 Canonical, Substs, Ty, TypeWalk, 17 BoundVar, Canonical, DebruijnIndex, Substs, Ty,
18}; 18};
19 19
20const AUTODEREF_RECURSION_LIMIT: usize = 10; 20const AUTODEREF_RECURSION_LIMIT: usize = 10;
@@ -61,14 +61,13 @@ fn deref_by_trait(
61 return None; 61 return None;
62 } 62 }
63 63
64 // FIXME make the Canonical handling nicer 64 // FIXME make the Canonical / bound var handling nicer
65 65
66 let parameters = Substs::build_for_generics(&generic_params) 66 let parameters =
67 .push(ty.value.value.clone().shift_bound_vars(1)) 67 Substs::build_for_generics(&generic_params).push(ty.value.value.clone()).build();
68 .build();
69 68
70 let projection = super::traits::ProjectionPredicate { 69 let projection = super::traits::ProjectionPredicate {
71 ty: Ty::Bound(0), 70 ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.num_vars)),
72 projection_ty: super::ProjectionTy { associated_ty: target, parameters }, 71 projection_ty: super::ProjectionTy { associated_ty: target, parameters },
73 }; 72 };
74 73
@@ -93,12 +92,16 @@ fn deref_by_trait(
93 // we have `impl<T> Deref for Foo<T> { Target = T }`, that should be 92 // we have `impl<T> Deref for Foo<T> { Target = T }`, that should be
94 // the case. 93 // the case.
95 for i in 1..vars.0.num_vars { 94 for i in 1..vars.0.num_vars {
96 if vars.0.value[i] != Ty::Bound((i - 1) as u32) { 95 if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
96 {
97 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution); 97 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution);
98 return None; 98 return None;
99 } 99 }
100 } 100 }
101 Some(Canonical { value: vars.0.value[0].clone(), num_vars: vars.0.num_vars }) 101 Some(Canonical {
102 value: vars.0.value[vars.0.value.len() - 1].clone(),
103 num_vars: vars.0.num_vars,
104 })
102 } 105 }
103 Solution::Ambig(_) => { 106 Solution::Ambig(_) => {
104 info!("Ambiguous solution for derefing {:?}: {:?}", ty.value, solution); 107 info!("Ambiguous solution for derefing {:?}: {:?}", ty.value, solution);
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index 0f8522021..8cbce1168 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -6,7 +6,7 @@ use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile};
6use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; 6use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
7use stdx::format_to; 7use stdx::format_to;
8 8
9pub use hir_def::diagnostics::UnresolvedModule; 9pub use hir_def::{diagnostics::UnresolvedModule, expr::MatchArm};
10pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; 10pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink};
11 11
12#[derive(Debug)] 12#[derive(Debug)]
@@ -63,6 +63,25 @@ impl AstDiagnostic for MissingFields {
63} 63}
64 64
65#[derive(Debug)] 65#[derive(Debug)]
66pub struct MissingMatchArms {
67 pub file: HirFileId,
68 pub match_expr: AstPtr<ast::Expr>,
69 pub arms: AstPtr<ast::MatchArmList>,
70}
71
72impl Diagnostic for MissingMatchArms {
73 fn message(&self) -> String {
74 String::from("Missing match arm")
75 }
76 fn source(&self) -> InFile<SyntaxNodePtr> {