From 8feed6aedb3731766241611481bb29c2d2ef62d0 Mon Sep 17 00:00:00 2001
From: Keith Yeung <kungfukeith11@gmail.com>
Date: Thu, 19 Aug 2021 02:24:55 -0700
Subject: [PATCH] Use proc macros to generate conversion functions for
 MultiLocation (#3635)

* Use proc macros to generate conversion functions for MultiLocation

* Add compile test and missing conversion cases

* Add common derives for Parent and Ancestor

* Generate conversion functions for MultiLocation v0 via proc macro

* Add type conversion test and fix a bug

* cargo fmt

* Do not hardcode 8 as the number of max parents

* Use map instead of for loops when generating code fragments

* Spelling

* cargo fmt

* More mapping, less for-looping
---
 polkadot/Cargo.lock                           |  10 +
 polkadot/Cargo.toml                           |   1 +
 polkadot/xcm/Cargo.toml                       |   1 +
 polkadot/xcm/procedural/Cargo.toml            |  13 +
 polkadot/xcm/procedural/src/lib.rs            |  36 ++
 polkadot/xcm/procedural/src/v0.rs             |  17 +
 .../xcm/procedural/src/v0/multilocation.rs    | 115 ++++
 polkadot/xcm/procedural/src/v1.rs             |  17 +
 .../xcm/procedural/src/v1/multilocation.rs    | 204 +++++++
 polkadot/xcm/src/v0/multi_location.rs         | 203 +------
 polkadot/xcm/src/v1/multilocation.rs          | 516 ++----------------
 11 files changed, 486 insertions(+), 647 deletions(-)
 create mode 100644 polkadot/xcm/procedural/Cargo.toml
 create mode 100644 polkadot/xcm/procedural/src/lib.rs
 create mode 100644 polkadot/xcm/procedural/src/v0.rs
 create mode 100644 polkadot/xcm/procedural/src/v0/multilocation.rs
 create mode 100644 polkadot/xcm/procedural/src/v1.rs
 create mode 100644 polkadot/xcm/procedural/src/v1/multilocation.rs

diff --git a/polkadot/Cargo.lock b/polkadot/Cargo.lock
index 2d262c8e94e..fce796875ae 100644
--- a/polkadot/Cargo.lock
+++ b/polkadot/Cargo.lock
@@ -11775,6 +11775,7 @@ dependencies = [
  "impl-trait-for-tuples",
  "log",
  "parity-scale-codec",
+ "xcm-procedural",
 ]
 
 [[package]]
@@ -11835,6 +11836,15 @@ dependencies = [
  "xcm-executor",
 ]
 
+[[package]]
+name = "xcm-procedural"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "xcm-simulator"
 version = "0.9.9"
diff --git a/polkadot/Cargo.toml b/polkadot/Cargo.toml
index ce6f8ddd1c5..3707b0b01c8 100644
--- a/polkadot/Cargo.toml
+++ b/polkadot/Cargo.toml
@@ -43,6 +43,7 @@ members = [
 	"xcm/xcm-simulator",
 	"xcm/xcm-simulator/example",
 	"xcm/pallet-xcm",
+	"xcm/procedural",
 	"node/client",
 	"node/collation-generation",
 	"node/core/approval-voting",
diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml
index a1bfa76130a..12b96a50216 100644
--- a/polkadot/xcm/Cargo.toml
+++ b/polkadot/xcm/Cargo.toml
@@ -10,6 +10,7 @@ impl-trait-for-tuples = "0.2.0"
 parity-scale-codec = { version = "2.0.0", default-features = false, features = [ "derive" ] }
 derivative = {version = "2.2.0", default-features = false, features = [ "use_core" ] }
 log = { version = "0.4.14", default-features = false }
+xcm-procedural = { path = "procedural" }
 
 [features]
 default = ["std"]
diff --git a/polkadot/xcm/procedural/Cargo.toml b/polkadot/xcm/procedural/Cargo.toml
new file mode 100644
index 00000000000..914efad452a
--- /dev/null
+++ b/polkadot/xcm/procedural/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+authors = ["Parity Technologies <admin@parity.io>"]
+name = "xcm-procedural"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro2 = "1.0.28"
+quote = "1.0.9"
+syn = "1.0.74"
diff --git a/polkadot/xcm/procedural/src/lib.rs b/polkadot/xcm/procedural/src/lib.rs
new file mode 100644
index 00000000000..fd6ffe55934
--- /dev/null
+++ b/polkadot/xcm/procedural/src/lib.rs
@@ -0,0 +1,36 @@
+// Copyright 2020 Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Procedural macros used in XCM.
+
+use proc_macro::TokenStream;
+
+mod v0;
+mod v1;
+
+#[proc_macro]
+pub fn impl_conversion_functions_for_multilocation_v0(input: TokenStream) -> TokenStream {
+	v0::multilocation::generate_conversion_functions(input)
+		.unwrap_or_else(syn::Error::into_compile_error)
+		.into()
+}
+
+#[proc_macro]
+pub fn impl_conversion_functions_for_multilocation_v1(input: TokenStream) -> TokenStream {
+	v1::multilocation::generate_conversion_functions(input)
+		.unwrap_or_else(syn::Error::into_compile_error)
+		.into()
+}
diff --git a/polkadot/xcm/procedural/src/v0.rs b/polkadot/xcm/procedural/src/v0.rs
new file mode 100644
index 00000000000..7774df4e9f8
--- /dev/null
+++ b/polkadot/xcm/procedural/src/v0.rs
@@ -0,0 +1,17 @@
+// Copyright 2021 Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+pub mod multilocation;
diff --git a/polkadot/xcm/procedural/src/v0/multilocation.rs b/polkadot/xcm/procedural/src/v0/multilocation.rs
new file mode 100644
index 00000000000..82db5cce4ee
--- /dev/null
+++ b/polkadot/xcm/procedural/src/v0/multilocation.rs
@@ -0,0 +1,115 @@
+// Copyright 2021 Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+use proc_macro2::{Span, TokenStream};
+use quote::{format_ident, quote};
+
+pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> syn::Result<TokenStream> {
+	if !input.is_empty() {
+		return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
+	}
+
+	let from_tuples = generate_conversion_from_tuples();
+	let from_v1 = generate_conversion_from_v1();
+
+	Ok(quote! {
+		#from_tuples
+		#from_v1
+	})
+}
+
+fn generate_conversion_from_tuples() -> TokenStream {
+	let from_tuples = (0..8usize)
+		.map(|num_junctions| {
+			let junctions =
+				(0..=num_junctions).map(|_| format_ident!("Junction")).collect::<Vec<_>>();
+			let idents = (0..=num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
+			let variant = &format_ident!("X{}", num_junctions + 1);
+			let array_size = num_junctions + 1;
+
+			quote! {
+				impl From<( #(#junctions,)* )> for MultiLocation {
+					fn from( ( #(#idents,)* ): ( #(#junctions,)* ) ) -> Self {
+						MultiLocation::#variant( #(#idents),* )
+					}
+				}
+
+				impl From<[Junction; #array_size]> for MultiLocation {
+					fn from(j: [Junction; #array_size]) -> Self {
+						let [#(#idents),*] = j;
+						MultiLocation::#variant( #(#idents),* )
+					}
+				}
+			}
+		})
+		.collect::<TokenStream>();
+
+	quote! {
+		impl From<()> for MultiLocation {
+			fn from(_: ()) -> Self {
+				MultiLocation::Null
+			}
+		}
+
+		impl From<Junction> for MultiLocation {
+			fn from(x: Junction) -> Self {
+				MultiLocation::X1(x)
+			}
+		}
+
+		impl From<[Junction; 0]> for MultiLocation {
+			fn from(_: [Junction; 0]) -> Self {
+				MultiLocation::Null
+			}
+		}
+
+		#from_tuples
+	}
+}
+
+fn generate_conversion_from_v1() -> TokenStream {
+	let match_variants = (0..8u8)
+		.map(|cur_num| {
+			let variant = format_ident!("X{}", cur_num + 1);
+			let idents = (1..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
+
+			quote! {
+				crate::v1::Junctions::#variant( j0 #(, #idents)* ) => res
+					.pushed_with(Junction::from(j0))
+					#( .and_then(|res| res.pushed_with(Junction::from(#idents))) )*
+					.map_err(|_| ()),
+			}
+		})
+		.collect::<TokenStream>();
+
+	quote! {
+		impl TryFrom<crate::v1::MultiLocation> for MultiLocation {
+			type Error = ();
+			fn try_from(v1: crate::v1::MultiLocation) -> core::result::Result<Self, ()> {
+				let mut res = MultiLocation::Null;
+
+				for _ in 0..v1.parents {
+					res.push(Junction::Parent)?;
+				}
+
+				match v1.interior {
+					crate::v1::Junctions::Here => Ok(res),
+					#match_variants
+				}
+			}
+		}
+	}
+}
diff --git a/polkadot/xcm/procedural/src/v1.rs b/polkadot/xcm/procedural/src/v1.rs
new file mode 100644
index 00000000000..7774df4e9f8
--- /dev/null
+++ b/polkadot/xcm/procedural/src/v1.rs
@@ -0,0 +1,17 @@
+// Copyright 2021 Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+pub mod multilocation;
diff --git a/polkadot/xcm/procedural/src/v1/multilocation.rs b/polkadot/xcm/procedural/src/v1/multilocation.rs
new file mode 100644
index 00000000000..c58f85ca31f
--- /dev/null
+++ b/polkadot/xcm/procedural/src/v1/multilocation.rs
@@ -0,0 +1,204 @@
+// Copyright 2021 Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+use proc_macro2::{Span, TokenStream};
+use quote::{format_ident, quote};
+use syn::{Result, Token};
+
+pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
+	if !input.is_empty() {
+		return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
+	}
+
+	// Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents.
+	let from_tuples = generate_conversion_from_tuples(8);
+	let from_v0 = generate_conversion_from_v0();
+
+	Ok(quote! {
+		#from_tuples
+		#from_v0
+	})
+}
+
+fn generate_conversion_from_tuples(max_parents: u8) -> TokenStream {
+	let mut from_tuples = (0..8usize)
+		.map(|num_junctions| {
+			let junctions =
+				(0..=num_junctions).map(|_| format_ident!("Junction")).collect::<Vec<_>>();
+			let idents = (0..=num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
+			let variant = &format_ident!("X{}", num_junctions + 1);
+			let array_size = num_junctions + 1;
+
+			let mut from_tuple = quote! {
+				impl From<( #(#junctions,)* )> for MultiLocation {
+					fn from( ( #(#idents,)* ): ( #(#junctions,)* ) ) -> Self {
+						MultiLocation { parents: 0, interior: Junctions::#variant( #(#idents),* ) }
+					}
+				}
+
+				impl From<(u8, #(#junctions),*)> for MultiLocation {
+					fn from( ( parents, #(#idents),* ): (u8, #(#junctions),* ) ) -> Self {
+						MultiLocation { parents, interior: Junctions::#variant( #(#idents),* ) }
+					}
+				}
+
+				impl From<(Ancestor, #(#junctions),*)> for MultiLocation {
+					fn from( ( Ancestor(parents), #(#idents),* ): (Ancestor, #(#junctions),* ) ) -> Self {
+						MultiLocation { parents, interior: Junctions::#variant( #(#idents),* ) }
+					}
+				}
+
+				impl From<[Junction; #array_size]> for MultiLocation {
+					fn from(j: [Junction; #array_size]) -> Self {
+						let [#(#idents),*] = j;
+						MultiLocation { parents: 0, interior: Junctions::#variant( #(#idents),* ) }
+					}
+				}
+			};
+
+			let from_parent_tuples = (1..=max_parents).map(|cur_parents| {
+				let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
+				let underscores =
+					(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
+
+				quote! {
+					impl From<( #(#parents,)* #(#junctions),* )> for MultiLocation {
+						fn from( (#(#underscores,)* #(#idents),*): ( #(#parents,)* #(#junctions),* ) ) -> Self {
+							MultiLocation { parents: #cur_parents, interior: Junctions::#variant( #(#idents),* ) }
+						}
+					}
+				}
+			});
+
+			from_tuple.extend(from_parent_tuples);
+			from_tuple
+		})
+		.collect::<TokenStream>();
+
+	let from_parent_junctions_tuples = (1..=max_parents).map(|cur_parents| {
+		let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
+		let underscores =
+			(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
+
+		quote! {
+			impl From<( #(#parents,)* Junctions )> for MultiLocation {
+				fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self {
+					MultiLocation { parents: #cur_parents, interior: junctions }
+				}
+			}
+		}
+	});
+	from_tuples.extend(from_parent_junctions_tuples);
+
+	quote! {
+		impl From<Junctions> for MultiLocation {
+			fn from(junctions: Junctions) -> Self {
+				MultiLocation { parents: 0, interior: junctions }
+			}
+		}
+
+		impl From<(u8, Junctions)> for MultiLocation {
+			fn from((parents, interior): (u8, Junctions)) -> Self {
+				MultiLocation { parents, interior }
+			}
+		}
+
+		impl From<(Ancestor, Junctions)> for MultiLocation {
+			fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self {
+				MultiLocation { parents, interior }
+			}
+		}
+
+		impl From<()> for MultiLocation {
+			fn from(_: ()) -> Self {
+				MultiLocation { parents: 0, interior: Junctions::Here }
+			}
+		}
+
+		impl From<(u8,)> for MultiLocation {
+			fn from((parents,): (u8,)) -> Self {
+				MultiLocation { parents, interior: Junctions::Here }
+			}
+		}
+
+		impl From<Junction> for MultiLocation {
+			fn from(x: Junction) -> Self {
+				MultiLocation { parents: 0, interior: Junctions::X1(x) }
+			}
+		}
+
+		impl From<[Junction; 0]> for MultiLocation {
+			fn from(_: [Junction; 0]) -> Self {
+				MultiLocation { parents: 0, interior: Junctions::Here }
+			}
+		}
+
+		#from_tuples
+	}
+}
+
+fn generate_conversion_from_v0() -> TokenStream {
+	let match_variants = (0..8u8)
+		.map(|cur_num| {
+			let num_ancestors = cur_num + 1;
+			let variant = format_ident!("X{}", num_ancestors);
+			let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
+
+			let intermediate_match_arms = (1..num_ancestors)
+				.rev()
+				.map(|parent_count| {
+					let parent_idents =
+						(0..parent_count).map(|j| format_ident!("j{}", j)).collect::<Vec<_>>();
+					let junction_idents = (parent_count..num_ancestors)
+						.map(|j| format_ident!("j{}", j))
+						.collect::<Vec<_>>();
+					let junction_variant = format_ident!("X{}", num_ancestors - parent_count);
+
+					quote! {
+						crate::v0::MultiLocation::#variant( #(#idents),* )
+							if #( #parent_idents.is_parent() )&&* =>
+							Ok(MultiLocation {
+								parents: #parent_count,
+								interior: #junction_variant( #( #junction_idents.try_into()? ),* ),
+							}),
+					}
+				})
+				.collect::<TokenStream>();
+
+			quote! {
+				crate::v0::MultiLocation::#variant( #(#idents),* )
+					if #( #idents.is_parent() )&&* =>
+					Ok(MultiLocation::ancestor(#num_ancestors)),
+				#intermediate_match_arms
+				crate::v0::MultiLocation::#variant( #(#idents),* ) =>
+					Ok( #variant( #( #idents.try_into()? ),* ).into() ),
+			}
+		})
+		.collect::<TokenStream>();
+
+	quote! {
+		impl TryFrom<crate::v0::MultiLocation> for MultiLocation {
+			type Error = ();
+			fn try_from(v0: crate::v0::MultiLocation) -> core::result::Result<Self, ()> {
+				use Junctions::*;
+				match v0 {
+					crate::v0::MultiLocation::Null => Ok(Here.into()),
+					#match_variants
+				}
+			}
+		}
+	}
+}
diff --git a/polkadot/xcm/src/v0/multi_location.rs b/polkadot/xcm/src/v0/multi_location.rs
index 89b10718647..1a6f4beb241 100644
--- a/polkadot/xcm/src/v0/multi_location.rs
+++ b/polkadot/xcm/src/v0/multi_location.rs
@@ -17,7 +17,6 @@
 //! Cross-Consensus Message format data structures.
 
 use super::Junction;
-use crate::v1::MultiLocation as MultiLocation1;
 use core::{convert::TryFrom, mem, result};
 use parity_scale_codec::{self, Decode, Encode};
 
@@ -68,117 +67,7 @@ pub enum MultiLocation {
 /// Maximum number of junctions a `MultiLocation` can contain.
 pub const MAX_MULTILOCATION_LENGTH: usize = 8;
 
-impl From<Junction> for MultiLocation {
-	fn from(x: Junction) -> Self {
-		MultiLocation::X1(x)
-	}
-}
-
-impl From<()> for MultiLocation {
-	fn from(_: ()) -> Self {
-		MultiLocation::Null
-	}
-}
-impl From<(Junction,)> for MultiLocation {
-	fn from(x: (Junction,)) -> Self {
-		MultiLocation::X1(x.0)
-	}
-}
-impl From<(Junction, Junction)> for MultiLocation {
-	fn from(x: (Junction, Junction)) -> Self {
-		MultiLocation::X2(x.0, x.1)
-	}
-}
-impl From<(Junction, Junction, Junction)> for MultiLocation {
-	fn from(x: (Junction, Junction, Junction)) -> Self {
-		MultiLocation::X3(x.0, x.1, x.2)
-	}
-}
-impl From<(Junction, Junction, Junction, Junction)> for MultiLocation {
-	fn from(x: (Junction, Junction, Junction, Junction)) -> Self {
-		MultiLocation::X4(x.0, x.1, x.2, x.3)
-	}
-}
-impl From<(Junction, Junction, Junction, Junction, Junction)> for MultiLocation {
-	fn from(x: (Junction, Junction, Junction, Junction, Junction)) -> Self {
-		MultiLocation::X5(x.0, x.1, x.2, x.3, x.4)
-	}
-}
-impl From<(Junction, Junction, Junction, Junction, Junction, Junction)> for MultiLocation {
-	fn from(x: (Junction, Junction, Junction, Junction, Junction, Junction)) -> Self {
-		MultiLocation::X6(x.0, x.1, x.2, x.3, x.4, x.5)
-	}
-}
-impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction)>
-	for MultiLocation
-{
-	fn from(x: (Junction, Junction, Junction, Junction, Junction, Junction, Junction)) -> Self {
-		MultiLocation::X7(x.0, x.1, x.2, x.3, x.4, x.5, x.6)
-	}
-}
-impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction)>
-	for MultiLocation
-{
-	fn from(
-		x: (Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction),
-	) -> Self {
-		MultiLocation::X8(x.0, x.1, x.2, x.3, x.4, x.5, x.6, x.7)
-	}
-}
-
-impl From<[Junction; 0]> for MultiLocation {
-	fn from(_: [Junction; 0]) -> Self {
-		MultiLocation::Null
-	}
-}
-impl From<[Junction; 1]> for MultiLocation {
-	fn from(x: [Junction; 1]) -> Self {
-		let [x0] = x;
-		MultiLocation::X1(x0)
-	}
-}
-impl From<[Junction; 2]> for MultiLocation {
-	fn from(x: [Junction; 2]) -> Self {
-		let [x0, x1] = x;
-		MultiLocation::X2(x0, x1)
-	}
-}
-impl From<[Junction; 3]> for MultiLocation {
-	fn from(x: [Junction; 3]) -> Self {
-		let [x0, x1, x2] = x;
-		MultiLocation::X3(x0, x1, x2)
-	}
-}
-impl From<[Junction; 4]> for MultiLocation {
-	fn from(x: [Junction; 4]) -> Self {
-		let [x0, x1, x2, x3] = x;
-		MultiLocation::X4(x0, x1, x2, x3)
-	}
-}
-impl From<[Junction; 5]> for MultiLocation {
-	fn from(x: [Junction; 5]) -> Self {
-		let [x0, x1, x2, x3, x4] = x;
-		MultiLocation::X5(x0, x1, x2, x3, x4)
-	}
-}
-impl From<[Junction; 6]> for MultiLocation {
-	fn from(x: [Junction; 6]) -> Self {
-		let [x0, x1, x2, x3, x4, x5] = x;
-		MultiLocation::X6(x0, x1, x2, x3, x4, x5)
-	}
-}
-impl From<[Junction; 7]> for MultiLocation {
-	fn from(x: [Junction; 7]) -> Self {
-		let [x0, x1, x2, x3, x4, x5, x6] = x;
-		MultiLocation::X7(x0, x1, x2, x3, x4, x5, x6)
-	}
-}
-impl From<[Junction; 8]> for MultiLocation {
-	fn from(x: [Junction; 8]) -> Self {
-		let [x0, x1, x2, x3, x4, x5, x6, x7] = x;
-		MultiLocation::X8(x0, x1, x2, x3, x4, x5, x6, x7)
-	}
-}
+xcm_procedural::impl_conversion_functions_for_multilocation_v0!();
 
 pub struct MultiLocationIterator(MultiLocation);
 impl Iterator for MultiLocationIterator {
@@ -696,75 +585,9 @@ impl MultiLocation {
 	}
 }
 
-impl TryFrom<MultiLocation1> for MultiLocation {
-	type Error = ();
-	fn try_from(v1: MultiLocation1) -> result::Result<Self, ()> {
-		use crate::v1::Junctions::*;
-		let mut res = Self::Null;
-
-		for _ in 0..v1.parents {
-			res.push(Junction::Parent)?;
-		}
-
-		match v1.interior {
-			Here => Ok(res),
-			X1(j0) => res.pushed_with(Junction::from(j0)).map_err(|_| ()),
-			X2(j0, j1) => res
-				.pushed_with(Junction::from(j0))
-				.and_then(|res| res.pushed_with(Junction::from(j1)))
-				.map_err(|_| ()),
-			X3(j0, j1, j2) => res
-				.pushed_with(Junction::from(j0))
-				.and_then(|res| res.pushed_with(Junction::from(j1)))
-				.and_then(|res| res.pushed_with(Junction::from(j2)))
-				.map_err(|_| ()),
-			X4(j0, j1, j2, j3) => res
-				.pushed_with(Junction::from(j0))
-				.and_then(|res| res.pushed_with(Junction::from(j1)))
-				.and_then(|res| res.pushed_with(Junction::from(j2)))
-				.and_then(|res| res.pushed_with(Junction::from(j3)))
-				.map_err(|_| ()),
-			X5(j0, j1, j2, j3, j4) => res
-				.pushed_with(Junction::from(j0))
-				.and_then(|res| res.pushed_with(Junction::from(j1)))
-				.and_then(|res| res.pushed_with(Junction::from(j2)))
-				.and_then(|res| res.pushed_with(Junction::from(j3)))
-				.and_then(|res| res.pushed_with(Junction::from(j4)))
-				.map_err(|_| ()),
-			X6(j0, j1, j2, j3, j4, j5) => res
-				.pushed_with(Junction::from(j0))
-				.and_then(|res| res.pushed_with(Junction::from(j1)))
-				.and_then(|res| res.pushed_with(Junction::from(j2)))
-				.and_then(|res| res.pushed_with(Junction::from(j3)))
-				.and_then(|res| res.pushed_with(Junction::from(j4)))
-				.and_then(|res| res.pushed_with(Junction::from(j5)))
-				.map_err(|_| ()),
-			X7(j0, j1, j2, j3, j4, j5, j6) => res
-				.pushed_with(Junction::from(j0))
-				.and_then(|res| res.pushed_with(Junction::from(j1)))
-				.and_then(|res| res.pushed_with(Junction::from(j2)))
-				.and_then(|res| res.pushed_with(Junction::from(j3)))
-				.and_then(|res| res.pushed_with(Junction::from(j4)))
-				.and_then(|res| res.pushed_with(Junction::from(j5)))
-				.and_then(|res| res.pushed_with(Junction::from(j6)))
-				.map_err(|_| ()),
-			X8(j0, j1, j2, j3, j4, j5, j6, j7) => res
-				.pushed_with(Junction::from(j0))
-				.and_then(|res| res.pushed_with(Junction::from(j1)))
-				.and_then(|res| res.pushed_with(Junction::from(j2)))
-				.and_then(|res| res.pushed_with(Junction::from(j3)))
-				.and_then(|res| res.pushed_with(Junction::from(j4)))
-				.and_then(|res| res.pushed_with(Junction::from(j5)))
-				.and_then(|res| res.pushed_with(Junction::from(j6)))
-				.and_then(|res| res.pushed_with(Junction::from(j7)))
-				.map_err(|_| ()),
-		}
-	}
-}
-
 #[cfg(test)]
 mod tests {
-	use super::MultiLocation::*;
+	use super::MultiLocation::{self, *};
 	use crate::opaque::v0::{Junction::*, NetworkId::Any};
 
 	#[test]
@@ -867,4 +690,26 @@ mod tests {
 		m.canonicalize();
 		assert_eq!(m, X4(Parent, Parent, Parachain(1), Parachain(2)));
 	}
+
+	#[test]
+	fn conversion_from_other_types_works() {
+		use crate::v1::{self, Junction, Junctions};
+		use core::convert::TryInto;
+
+		fn takes_multilocation<Arg: Into<MultiLocation>>(_arg: Arg) {}
+
+		takes_multilocation(Null);
+		takes_multilocation(Parent);
+		takes_multilocation([Parent, Parachain(4)]);
+
+		assert_eq!(v1::MultiLocation::here().try_into(), Ok(MultiLocation::Null));
+		assert_eq!(
+			v1::MultiLocation::new(1, Junctions::X1(Junction::Parachain(8))).try_into(),
+			Ok(X2(Parent, Parachain(8))),
+		);
+		assert_eq!(
+			v1::MultiLocation::new(24, Junctions::Here).try_into(),
+			Err::<MultiLocation, ()>(()),
+		);
+	}
 }
diff --git a/polkadot/xcm/src/v1/multilocation.rs b/polkadot/xcm/src/v1/multilocation.rs
index b90c5489273..d702422b6d0 100644
--- a/polkadot/xcm/src/v1/multilocation.rs
+++ b/polkadot/xcm/src/v1/multilocation.rs
@@ -17,7 +17,6 @@
 //! Cross-Consensus Message format data structures.
 
 use super::Junction;
-use crate::v0::MultiLocation as MultiLocation0;
 use core::{
 	convert::{TryFrom, TryInto},
 	mem, result,
@@ -315,6 +314,7 @@ impl MultiLocation {
 }
 
 /// A unit struct which can be converted into a `MultiLocation` of `parents` value 1.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
 pub struct Parent;
 impl From<Parent> for MultiLocation {
 	fn from(_: Parent) -> Self {
@@ -323,6 +323,7 @@ impl From<Parent> for MultiLocation {
 }
 
 /// A tuple struct which can be converted into a `MultiLocation` of `parents` value 1 with the inner interior.
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
 pub struct ParentThen(Junctions);
 impl From<ParentThen> for MultiLocation {
 	fn from(x: ParentThen) -> Self {
@@ -331,6 +332,7 @@ impl From<ParentThen> for MultiLocation {
 }
 
 /// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
 pub struct Ancestor(u8);
 impl From<Ancestor> for MultiLocation {
 	fn from(x: Ancestor) -> Self {
@@ -339,6 +341,7 @@ impl From<Ancestor> for MultiLocation {
 }
 
 /// A unit struct which can be converted into a `MultiLocation` of the inner `parents` value and the inner interior.
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
 pub struct AncestorThen(u8, Junctions);
 impl From<AncestorThen> for MultiLocation {
 	fn from(x: AncestorThen) -> Self {
@@ -346,217 +349,7 @@ impl From<AncestorThen> for MultiLocation {
 	}
 }
 
-impl From<Junctions> for MultiLocation {
-	fn from(junctions: Junctions) -> Self {
-		MultiLocation { parents: 0, interior: junctions }
-	}
-}
-
-impl From<(u8, Junctions)> for MultiLocation {
-	fn from((parents, interior): (u8, Junctions)) -> Self {
-		MultiLocation { parents, interior }
-	}
-}
-
-impl From<Junction> for MultiLocation {
-	fn from(x: Junction) -> Self {
-		MultiLocation { parents: 0, interior: Junctions::X1(x) }
-	}
-}
-
-impl From<()> for MultiLocation {
-	fn from(_: ()) -> Self {
-		MultiLocation { parents: 0, interior: Junctions::Here }
-	}
-}
-impl From<(Junction,)> for MultiLocation {
-	fn from(x: (Junction,)) -> Self {
-		MultiLocation { parents: 0, interior: Junctions::X1(x.0) }
-	}
-}
-impl From<(Junction, Junction)> for MultiLocation {
-	fn from(x: (Junction, Junction)) -> Self {
-		MultiLocation { parents: 0, interior: Junctions::X2(x.0, x.1) }
-	}
-}
-impl From<(Junction, Junction, Junction)> for MultiLocation {
-	fn from(x: (Junction, Junction, Junction)) -> Self {
-		MultiLocation { parents: 0, interior: Junctions::X3(x.0, x.1, x.2) }
-	}
-}
-impl From<(Junction, Junction, Junction, Junction)> for MultiLocation {
-	fn from(x: (Junction, Junction, Junction, Junction)) -> Self {
-		MultiLocation { parents: 0, interior: Junctions::X4(x.0, x.1, x.2, x.3) }
-	}
-}
-impl From<(Junction, Junction, Junction, Junction, Junction)> for MultiLocation {
-	fn from(x: (Junction, Junction, Junction, Junction, Junction)) -> Self {
-		MultiLocation { parents: 0, interior: Junctions::X5(x.0, x.1, x.2, x.3, x.4) }
-	}
-}
-impl From<(Junction, Junction, Junction, Junction, Junction, Junction)> for MultiLocation {
-	fn from(x: (Junction, Junction, Junction, Junction, Junction, Junction)) -> Self {
-		MultiLocation { parents: 0, interior: Junctions::X6(x.0, x.1, x.2, x.3, x.4, x.5) }
-	}
-}
-impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction)>
-	for MultiLocation
-{
-	fn from(x: (Junction, Junction, Junction, Junction, Junction, Junction, Junction)) -> Self {
-		MultiLocation { parents: 0, interior: Junctions::X7(x.0, x.1, x.2, x.3, x.4, x.5, x.6) }
-	}
-}
-impl From<(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction)>
-	for MultiLocation
-{
-	fn from(
-		x: (Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction),
-	) -> Self {
-		MultiLocation {
-			parents: 0,
-			interior: Junctions::X8(x.0, x.1, x.2, x.3, x.4, x.5, x.6, x.7),
-		}
-	}
-}
-
-impl From<(u8,)> for MultiLocation {
-	fn from((parents,): (u8,)) -> Self {
-		MultiLocation { parents, interior: Junctions::Here }
-	}
-}
-impl From<(u8, Junction)> for MultiLocation {
-	fn from((parents, j0): (u8, Junction)) -> Self {
-		MultiLocation { parents, interior: Junctions::X1(j0) }
-	}
-}
-impl From<(u8, Junction, Junction)> for MultiLocation {
-	fn from((parents, j0, j1): (u8, Junction, Junction)) -> Self {
-		MultiLocation { parents, interior: Junctions::X2(j0, j1) }
-	}
-}
-impl From<(u8, Junction, Junction, Junction)> for MultiLocation {
-	fn from((parents, j0, j1, j2): (u8, Junction, Junction, Junction)) -> Self {
-		MultiLocation { parents, interior: Junctions::X3(j0, j1, j2) }
-	}
-}
-impl From<(u8, Junction, Junction, Junction, Junction)> for MultiLocation {
-	fn from((parents, j0, j1, j2, j3): (u8, Junction, Junction, Junction, Junction)) -> Self {
-		MultiLocation { parents, interior: Junctions::X4(j0, j1, j2, j3) }
-	}
-}
-impl From<(u8, Junction, Junction, Junction, Junction, Junction)> for MultiLocation {
-	fn from(
-		(parents, j0, j1, j2, j3, j4): (u8, Junction, Junction, Junction, Junction, Junction),
-	) -> Self {
-		MultiLocation { parents, interior: Junctions::X5(j0, j1, j2, j3, j4) }
-	}
-}
-impl From<(u8, Junction, Junction, Junction, Junction, Junction, Junction)> for MultiLocation {
-	fn from(
-		(parents, j0, j1, j2, j3, j4, j5): (
-			u8,
-			Junction,
-			Junction,
-			Junction,
-			Junction,
-			Junction,
-			Junction,
-		),
-	) -> Self {
-		MultiLocation { parents, interior: Junctions::X6(j0, j1, j2, j3, j4, j5) }
-	}
-}
-impl From<(u8, Junction, Junction, Junction, Junction, Junction, Junction, Junction)>
-	for MultiLocation
-{
-	fn from(
-		(parents, j0, j1, j2, j3, j4, j5, j6): (
-			u8,
-			Junction,
-			Junction,
-			Junction,
-			Junction,
-			Junction,
-			Junction,
-			Junction,
-		),
-	) -> Self {
-		MultiLocation { parents, interior: Junctions::X7(j0, j1, j2, j3, j4, j5, j6) }
-	}
-}
-impl From<(u8, Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction)>
-	for MultiLocation
-{
-	fn from(
-		(parents, j0, j1, j2, j3, j4, j5, j6, j7): (
-			u8,
-			Junction,
-			Junction,
-			Junction,
-			Junction,
-			Junction,
-			Junction,
-			Junction,
-			Junction,
-		),
-	) -> Self {
-		MultiLocation { parents, interior: Junctions::X8(j0, j1, j2, j3, j4, j5, j6, j7) }
-	}
-}
-
-impl From<[Junction; 0]> for MultiLocation {
-	fn from(_: [Junction; 0]) -> Self {
-		MultiLocation { parents: 0, interior: Junctions::Here }
-	}
-}
-impl From<[Junction; 1]> for MultiLocation {
-	fn from(x: [Junction; 1]) -> Self {
-		let [x0] = x;
-		MultiLocation { parents: 0, interior: Junctions::X1(x0) }
-	}
-}
-impl From<[Junction; 2]> for MultiLocation {
-	fn from(x: [Junction; 2]) -> Self {
-		let [x0, x1] = x;
-		MultiLocation { parents: 0, interior: Junctions::X2(x0, x1) }
-	}
-}
-impl From<[Junction; 3]> for MultiLocation {
-	fn from(x: [Junction; 3]) -> Self {
-		let [x0, x1, x2] = x;
-		MultiLocation { parents: 0, interior: Junctions::X3(x0, x1, x2) }
-	}
-}
-impl From<[Junction; 4]> for MultiLocation {
-	fn from(x: [Junction; 4]) -> Self {
-		let [x0, x1, x2, x3] = x;
-		MultiLocation { parents: 0, interior: Junctions::X4(x0, x1, x2, x3) }
-	}
-}
-impl From<[Junction; 5]> for MultiLocation {
-	fn from(x: [Junction; 5]) -> Self {
-		let [x0, x1, x2, x3, x4] = x;
-		MultiLocation { parents: 0, interior: Junctions::X5(x0, x1, x2, x3, x4) }
-	}
-}
-impl From<[Junction; 6]> for MultiLocation {
-	fn from(x: [Junction; 6]) -> Self {
-		let [x0, x1, x2, x3, x4, x5] = x;
-		MultiLocation { parents: 0, interior: Junctions::X6(x0, x1, x2, x3, x4, x5) }
-	}
-}
-impl From<[Junction; 7]> for MultiLocation {
-	fn from(x: [Junction; 7]) -> Self {
-		let [x0, x1, x2, x3, x4, x5, x6] = x;
-		MultiLocation { parents: 0, interior: Junctions::X7(x0, x1, x2, x3, x4, x5, x6) }
-	}
-}
-impl From<[Junction; 8]> for MultiLocation {
-	fn from(x: [Junction; 8]) -> Self {
-		let [x0, x1, x2, x3, x4, x5, x6, x7] = x;
-		MultiLocation { parents: 0, interior: Junctions::X8(x0, x1, x2, x3, x4, x5, x6, x7) }
-	}
-}
+xcm_procedural::impl_conversion_functions_for_multilocation_v1!();
 
 /// Maximum number of `Junction`s that a `Junctions` can contain.
 const MAX_JUNCTIONS: usize = 8;
@@ -965,264 +758,9 @@ impl TryFrom<MultiLocation> for Junctions {
 	}
 }
 
-impl TryFrom<MultiLocation0> for MultiLocation {
-	type Error = ();
-	fn try_from(old: MultiLocation0) -> result::Result<Self, ()> {
-		use Junctions::*;
-		match old {
-			MultiLocation0::Null => Ok(Here.into()),
-			MultiLocation0::X1(j0) if j0.is_parent() => Ok(Parent.into()),
-			MultiLocation0::X1(j0) => Ok(X1(j0.try_into()?).into()),
-			MultiLocation0::X2(j0, j1) if j0.is_parent() && j1.is_parent() =>
-				Ok(MultiLocation::grandparent()),
-			MultiLocation0::X2(j0, j1) if j0.is_parent() =>
-				Ok(MultiLocation { parents: 1, interior: X1(j1.try_into()?) }),
-			MultiLocation0::X2(j0, j1) => Ok(X2(j0.try_into()?, j1.try_into()?).into()),
-			MultiLocation0::X3(j0, j1, j2)
-				if j0.is_parent() && j1.is_parent() && j2.is_parent() =>
-				Ok(MultiLocation::ancestor(3)),
-			MultiLocation0::X3(j0, j1, j2) if j0.is_parent() && j1.is_parent() =>
-				Ok(MultiLocation { parents: 2, interior: X1(j2.try_into()?) }),
-			MultiLocation0::X3(j0, j1, j2) if j0.is_parent() =>
-				Ok(MultiLocation { parents: 1, interior: X2(j1.try_into()?, j2.try_into()?) }),
-			MultiLocation0::X3(j0, j1, j2) =>
-				Ok(X3(j0.try_into()?, j1.try_into()?, j2.try_into()?).into()),
-			MultiLocation0::X4(j0, j1, j2, j3)
-				if j0.is_parent() && j1.is_parent() && j2.is_parent() && j3.is_parent() =>
-				Ok(MultiLocation::ancestor(4)),
-			MultiLocation0::X4(j0, j1, j2, j3)
-				if j0.is_parent() && j1.is_parent() && j2.is_parent() =>
-				Ok(MultiLocation { parents: 3, interior: X1(j3.try_into()?) }),
-			MultiLocation0::X4(j0, j1, j2, j3) if j0.is_parent() && j1.is_parent() =>
-				Ok(MultiLocation { parents: 2, interior: X2(j2.try_into()?, j3.try_into()?) }),
-			MultiLocation0::X4(j0, j1, j2, j3) if j0.is_parent() => Ok(MultiLocation {
-				parents: 1,
-				interior: X3(j1.try_into()?, j2.try_into()?, j3.try_into()?),
-			}),
-			MultiLocation0::X4(j0, j1, j2, j3) =>
-				Ok(X4(j0.try_into()?, j1.try_into()?, j2.try_into()?, j3.try_into()?).into()),
-			MultiLocation0::X5(j0, j1, j2, j3, j4)
-				if j0.is_parent() &&
-					j1.is_parent() && j2.is_parent() &&
-					j3.is_parent() && j4.is_parent() =>
-				Ok(MultiLocation::ancestor(5)),
-			MultiLocation0::X5(j0, j1, j2, j3, j4)
-				if j0.is_parent() && j1.is_parent() && j2.is_parent() && j3.is_parent() =>
-				Ok(MultiLocation { parents: 4, interior: X1(j4.try_into()?) }),
-			MultiLocation0::X5(j0, j1, j2, j3, j4)
-				if j0.is_parent() && j1.is_parent() && j2.is_parent() =>
-				Ok(MultiLocation { parents: 3, interior: X2(j3.try_into()?, j4.try_into()?) }),
-			MultiLocation0::X5(j0, j1, j2, j3, j4) if j0.is_parent() && j1.is_parent() =>
-				Ok(MultiLocation {
-					parents: 2,
-					interior: X3(j2.try_into()?, j3.try_into()?, j4.try_into()?),
-				}),
-			MultiLocation0::X5(j0, j1, j2, j3, j4) if j0.is_parent() => Ok(MultiLocation {
-				parents: 1,
-				interior: X4(j1.try_into()?, j2.try_into()?, j3.try_into()?, j4.try_into()?),
-			}),
-			MultiLocation0::X5(j0, j1, j2, j3, j4) => Ok(X5(
-				j0.try_into()?,
-				j1.try_into()?,
-				j2.try_into()?,
-				j3.try_into()?,
-				j4.try_into()?,
-			)
-			.into()),
-			MultiLocation0::X6(j0, j1, j2, j3, j4, j5)
-				if j0.is_parent() &&
-					j1.is_parent() && j2.is_parent() &&
-					j3.is_parent() && j4.is_parent() &&
-					j5.is_parent() =>
-				Ok(MultiLocation::ancestor(6)),
-			MultiLocation0::X6(j0, j1, j2, j3, j4, j5)
-				if j0.is_parent() &&
-					j1.is_parent() && j2.is_parent() &&
-					j3.is_parent() && j4.is_parent() =>
-				Ok(MultiLocation { parents: 5, interior: X1(j5.try_into()?) }),
-			MultiLocation0::X6(j0, j1, j2, j3, j4, j5)
-				if j0.is_parent() && j1.is_parent() && j2.is_parent() && j3.is_parent() =>
-				Ok(MultiLocation { parents: 4, interior: X2(j4.try_into()?, j5.try_into()?) }),
-			MultiLocation0::X6(j0, j1, j2, j3, j4, j5)
-				if j0.is_parent() && j1.is_parent() && j2.is_parent() =>
-				Ok(MultiLocation {
-					parents: 3,
-					interior: X3(j3.try_into()?, j4.try_into()?, j5.try_into()?),
-				}),
-			MultiLocation0::X6(j0, j1, j2, j3, j4, j5) if j0.is_parent() && j1.is_parent() =>
-				Ok(MultiLocation {
-					parents: 2,
-					interior: X4(j2.try_into()?, j3.try_into()?, j4.try_into()?, j5.try_into()?),
-				}),
-			MultiLocation0::X6(j0, j1, j2, j3, j4, j5) if j0.is_parent() => Ok(MultiLocation {
-				parents: 1,
-				interior: X5(
-					j1.try_into()?,
-					j2.try_into()?,
-					j3.try_into()?,
-					j4.try_into()?,
-					j5.try_into()?,
-				),
-			}),
-			MultiLocation0::X6(j0, j1, j2, j3, j4, j5) => Ok(X6(
-				j0.try_into()?,
-				j1.try_into()?,
-				j2.try_into()?,
-				j3.try_into()?,
-				j4.try_into()?,
-				j5.try_into()?,
-			)
-			.into()),
-			MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6)
-				if j0.is_parent() &&
-					j1.is_parent() && j2.is_parent() &&
-					j3.is_parent() && j4.is_parent() &&
-					j5.is_parent() && j6.is_parent() =>
-				Ok(MultiLocation::ancestor(7)),
-			MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6)
-				if j0.is_parent() &&
-					j1.is_parent() && j2.is_parent() &&
-					j3.is_parent() && j4.is_parent() &&
-					j5.is_parent() =>
-				Ok(MultiLocation { parents: 6, interior: X1(j6.try_into()?) }),
-			MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6)
-				if j0.is_parent() &&
-					j1.is_parent() && j2.is_parent() &&
-					j3.is_parent() && j4.is_parent() =>
-				Ok(MultiLocation { parents: 5, interior: X2(j5.try_into()?, j6.try_into()?) }),
-			MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6)
-				if j0.is_parent() && j1.is_parent() && j2.is_parent() && j3.is_parent() =>
-				Ok(MultiLocation {
-					parents: 4,
-					interior: X3(j4.try_into()?, j5.try_into()?, j6.try_into()?),
-				}),
-			MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6)
-				if j0.is_parent() && j1.is_parent() && j2.is_parent() =>
-				Ok(MultiLocation {
-					parents: 3,
-					interior: X4(j3.try_into()?, j4.try_into()?, j5.try_into()?, j6.try_into()?),
-				}),
-			MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6) if j0.is_parent() && j1.is_parent() =>
-				Ok(MultiLocation {
-					parents: 2,
-					interior: X5(
-						j2.try_into()?,
-						j3.try_into()?,
-						j4.try_into()?,
-						j5.try_into()?,
-						j6.try_into()?,
-					),
-				}),
-			MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6) if j0.is_parent() => Ok(MultiLocation {
-				parents: 1,
-				interior: X6(
-					j1.try_into()?,
-					j2.try_into()?,
-					j3.try_into()?,
-					j4.try_into()?,
-					j5.try_into()?,
-					j6.try_into()?,
-				),
-			}),
-			MultiLocation0::X7(j0, j1, j2, j3, j4, j5, j6) => Ok(X7(
-				j0.try_into()?,
-				j1.try_into()?,
-				j2.try_into()?,
-				j3.try_into()?,
-				j4.try_into()?,
-				j5.try_into()?,
-				j6.try_into()?,
-			)
-			.into()),
-			MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7)
-				if j0.is_parent() &&
-					j1.is_parent() && j2.is_parent() &&
-					j3.is_parent() && j4.is_parent() &&
-					j5.is_parent() && j6.is_parent() &&
-					j7.is_parent() =>
-				Ok(MultiLocation::ancestor(8)),
-			MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7)
-				if j0.is_parent() &&
-					j1.is_parent() && j2.is_parent() &&
-					j3.is_parent() && j4.is_parent() &&
-					j5.is_parent() && j6.is_parent() =>
-				Ok(MultiLocation { parents: 7, interior: X1(j7.try_into()?) }),
-			MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7)
-				if j0.is_parent() &&
-					j1.is_parent() && j2.is_parent() &&
-					j3.is_parent() && j4.is_parent() &&
-					j5.is_parent() =>
-				Ok(MultiLocation { parents: 6, interior: X2(j6.try_into()?, j7.try_into()?) }),
-			MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7)
-				if j0.is_parent() &&
-					j1.is_parent() && j2.is_parent() &&
-					j3.is_parent() && j4.is_parent() =>
-				Ok(MultiLocation {
-					parents: 5,
-					interior: X3(j5.try_into()?, j6.try_into()?, j7.try_into()?),
-				}),
-			MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7)
-				if j0.is_parent() && j1.is_parent() && j2.is_parent() && j3.is_parent() =>
-				Ok(MultiLocation {
-					parents: 4,
-					interior: X4(j4.try_into()?, j5.try_into()?, j6.try_into()?, j7.try_into()?),
-				}),
-			MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7)
-				if j0.is_parent() && j1.is_parent() && j2.is_parent() =>
-				Ok(MultiLocation {
-					parents: 3,
-					interior: X5(
-						j3.try_into()?,
-						j4.try_into()?,
-						j5.try_into()?,
-						j6.try_into()?,
-						j7.try_into()?,
-					),
-				}),
-			MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7)
-				if j0.is_parent() && j1.is_parent() =>
-				Ok(MultiLocation {
-					parents: 2,
-					interior: X6(
-						j2.try_into()?,
-						j3.try_into()?,
-						j4.try_into()?,
-						j5.try_into()?,
-						j6.try_into()?,
-						j7.try_into()?,
-					),
-				}),
-			MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7) if j0.is_parent() =>
-				Ok(MultiLocation {
-					parents: 1,
-					interior: X7(
-						j1.try_into()?,
-						j2.try_into()?,
-						j3.try_into()?,
-						j4.try_into()?,
-						j5.try_into()?,
-						j6.try_into()?,
-						j7.try_into()?,
-					),
-				}),
-			MultiLocation0::X8(j0, j1, j2, j3, j4, j5, j6, j7) => Ok(X8(
-				j0.try_into()?,
-				j1.try_into()?,
-				j2.try_into()?,
-				j3.try_into()?,
-				j4.try_into()?,
-				j5.try_into()?,
-				j6.try_into()?,
-				j7.try_into()?,
-			)
-			.into()),
-		}
-	}
-}
-
 #[cfg(test)]
 mod tests {
-	use super::{Junctions::*, MultiLocation};
+	use super::{Ancestor, AncestorThen, Junctions::*, MultiLocation, Parent, ParentThen};
 	use crate::opaque::v1::{Junction::*, NetworkId::Any};
 	use parity_scale_codec::{Decode, Encode};
 
@@ -1330,4 +868,46 @@ mod tests {
 		assert_eq!(iter.next(), None);
 		assert_eq!(iter.next_back(), None);
 	}
+
+	#[test]
+	fn conversion_from_other_types_works() {
+		use crate::v0;
+		use core::convert::TryInto;
+
+		fn takes_multilocation<Arg: Into<MultiLocation>>(_arg: Arg) {}
+
+		takes_multilocation(Parent);
+		takes_multilocation(Here);
+		takes_multilocation(X1(Parachain(42)));
+		takes_multilocation((255, PalletInstance(8)));
+		takes_multilocation((Ancestor(5), Parachain(1), PalletInstance(3)));
+		takes_multilocation((Ancestor(2), Here));
+		takes_multilocation(AncestorThen(
+			3,
+			X2(Parachain(43), AccountIndex64 { network: Any, index: 155 }),
+		));
+		takes_multilocation((Parent, AccountId32 { network: Any, id: [0; 32] }));
+		takes_multilocation((Parent, Here));
+		takes_multilocation(ParentThen(X1(Parachain(75))));
+		takes_multilocation([Parachain(100), PalletInstance(3)]);
+
+		assert_eq!(v0::MultiLocation::Null.try_into(), Ok(MultiLocation::here()));
+		assert_eq!(
+			v0::MultiLocation::X1(v0::Junction::Parent).try_into(),
+			Ok(MultiLocation::parent())
+		);
+		assert_eq!(
+			v0::MultiLocation::X2(v0::Junction::Parachain(88), v0::Junction::Parent).try_into(),
+			Err::<MultiLocation, ()>(()),
+		);
+		assert_eq!(
+			v0::MultiLocation::X3(
+				v0::Junction::Parent,
+				v0::Junction::Parent,
+				v0::Junction::GeneralKey(b"foo".to_vec()),
+			)
+			.try_into(),
+			Ok(MultiLocation { parents: 2, interior: X1(GeneralKey(b"foo".to_vec())) }),
+		);
+	}
 }
-- 
GitLab